Se eu tiver uma classe util com métodos estáticos que chamarão as funções do Hibernate para obter acesso básico aos dados. Eu estou querendo saber se fazer o método synchronized
é a abordagem correta para garantir a segurança do thread.
Quero que isso impeça o acesso de informações à mesma instância de banco de dados. No entanto, agora tenho certeza se o código a seguir está impedindo getObjectById
a chamada para todas as classes quando é chamado por uma classe específica.
public class Utils {
public static synchronized Object getObjectById (Class objclass, Long id) {
// call hibernate class
Session session = new Configuration().configure().buildSessionFactory().openSession();
Object obj = session.load(objclass, id);
session.close();
return obj;
}
// other static methods
}
For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
Portanto, se um encadeamento entrar em um método estático, o mesmo objeto retornado pelo Object # getClass será bloqueado. Outros threads ainda podem acessar métodos de instância.Class
objeto instanciado por um dos carregadores de classe de máquinas virtuais. Como todos os objetos, esse objeto também tem umMonitor
associado. E esse monitor é o que está sendo bloqueado.Para abordar a questão de maneira mais geral ...
Lembre-se de que o uso de métodos sincronizados é realmente apenas uma abreviação (suponha que a classe seja SomeClass):
é o mesmo que
e
é o mesmo que
Você pode usar qualquer objeto como a trava. Se você deseja bloquear subconjuntos de métodos estáticos, pode
(para métodos não estáticos, você gostaria que os bloqueios fossem campos não estáticos)
fonte
Os métodos estáticos usam a classe como objeto de bloqueio, que é Utils.class no seu exemplo. Então sim, está tudo bem.
fonte
static synchronized
significa segurar a trava noClass
objeto da classe, ondesynchronized
significa segurar a trava no próprio objeto da classe. Isso significa que, se você estiver acessando um método sincronizado não estático em um encadeamento (de execução), ainda poderá acessar um método sincronizado estático usando outro encadeamento.Portanto, não é possível acessar dois mesmos tipos de métodos (dois métodos estáticos ou dois métodos não estáticos) a qualquer momento por mais de um encadeamento.
fonte
Por que você deseja impor que apenas um único encadeamento possa acessar o banco de dados a qualquer momento?
É tarefa do driver do banco de dados implementar qualquer bloqueio necessário, assumindo uma
Connection
seja usada apenas por um encadeamento de cada vez!Provavelmente, seu banco de dados é perfeitamente capaz de lidar com vários acessos paralelos
fonte
Se tem algo a ver com os dados do seu banco de dados, por que não utilizar o bloqueio de isolamento do banco de dados para obter isso?
fonte
Para responder à sua pergunta, sim: ele não
synchronized
pode ser executado por mais de um thread por vez.fonte
Como a
synchronized
palavra-chave Java funcionaQuando você adiciona a
synchronized
palavra-chave a um método estático, o método pode ser chamado apenas por um único thread por vez.No seu caso, toda chamada de método irá:
SessionFactory
Session
No entanto, esses eram seus requisitos:
getObjectById
ser chamado para todas as classes quando é chamado por uma classe específicaPortanto, mesmo que o
getObjectById
método seja seguro para threads, a implementação está errada.SessionFactory
Melhores PráticasO
SessionFactory
thread é seguro e é um objeto muito caro para criar, pois precisa analisar as classes de entidade e criar a representação interna do metamodelo da entidade.Portanto, você não deve criar a chamada
SessionFactory
a cadagetObjectById
método.Em vez disso, você deve criar uma instância singleton para ela.
O
Session
deve sempre estar fechadoVocê não fechar o
Session
em umfinally
bloco, e isso pode vazar recursos de banco de dados se uma exceção é lançada quando o carregamento da entidade.De acordo com o
Session.load
método, o JavaDoc pode lançar aHibernateException
se a entidade não puder ser encontrada no banco de dados.É por isso que você precisa usar um
finally
bloco para fechar oSession
seguinte:Impedindo o acesso multithread
No seu caso, você queria garantir que apenas um encadeamento tenha acesso a essa entidade específica.
Mas a
synchronized
palavra - chave impede apenas que dois threads chamem ogetObjectById
concorrente. Se os dois threads chamarem esse método um após o outro, você ainda terá dois threads usando essa entidade.Portanto, se você deseja bloquear um determinado objeto de banco de dados para que nenhum outro encadeamento possa modificá-lo, será necessário usar bloqueios de banco de dados.
A
synchronized
palavra-chave funciona apenas em uma única JVM. Se você tiver vários nós da web, isso não impedirá o acesso multiencadeado em várias JVMs.O que você precisa fazer é usar
LockModeType.PESSIMISTIC_READ
ouLockModeType.PESSIMISTIC_WRITE
ao aplicar as alterações no banco de dados, assim:Então, foi o que eu fiz:
EntityTransaction
e iniciei uma nova transação de banco de dadosPost
entidade enquanto mantinha um bloqueio no registro do banco de dados associadoPost
entidade e comprometi a transaçãoException
ser jogado, reverti a transaçãofonte