Si j'ai une classe util avec des méthodes statiques qui appelleront les fonctions Hibernate pour accéder aux données de base. Je me demande si l'élaboration de la méthode synchronized
est la bonne approche pour garantir la sécurité des threads.
Je veux que cela empêche l'accès des informations à la même instance de base de données. Cependant, je suis maintenant sûr que le code suivant empêche d' getObjectById
être appelé pour toutes les classes lorsqu'il est appelé par une classe particulière.
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.
Ainsi, si un thread entre dans une méthode statique, le même objet renvoyé par Object # getClass est verrouillé. D'autres threads peuvent toujours accéder aux méthodes d'instance.Class
objet, instancié par l'un des chargeurs de classe des machines virtuelles. Comme tous les objets, cet objet a également unMonitor
associé. Et ce moniteur est ce qui est verrouillé.Pour aborder la question plus généralement ...
Gardez à l'esprit que l'utilisation de méthodes synchronisées n'est en réalité qu'un raccourci (supposons que la classe est SomeClass):
est le même que
et
est le même que
Vous pouvez utiliser n'importe quel objet comme verrou. Si vous souhaitez verrouiller des sous-ensembles de méthodes statiques, vous pouvez
(pour les méthodes non statiques, vous voudriez que les verrous soient des champs non statiques)
la source
Les méthodes statiques utilisent la classe comme objet de verrouillage, qui est Utils.class pour votre exemple. Alors oui, ça va.
la source
static synchronized
signifie maintenir le verrou sur l'Class
objet de la classe alors que celasynchronized
signifie maintenir le verrou sur l'objet de cette classe lui-même. Cela signifie que si vous accédez à une méthode synchronisée non statique dans un thread (d'exécution), vous pouvez toujours accéder à une méthode synchronisée statique à l'aide d'un autre thread.Ainsi, accéder à deux méthodes du même type (soit deux méthodes statiques soit deux méthodes non statiques) à tout moment par plus d'un thread n'est pas possible.
la source
Pourquoi voulez-vous imposer qu'un seul thread puisse accéder à la base de données à la fois?
C'est le travail du pilote de base de données d'implémenter tout verrouillage nécessaire, en supposant que a
Connection
n'est utilisé que par un thread à la fois!Très probablement, votre base de données est parfaitement capable de gérer plusieurs accès parallèles
la source
S'il s'agit de quelque chose à voir avec les données de votre base de données, pourquoi ne pas utiliser le verrouillage d'isolation de base de données pour y parvenir?
la source
Pour répondre à votre question, oui: votre
synchronized
méthode ne peut pas être exécutée par plus d'un thread à la fois.la source
Fonctionnement du
synchronized
mot-clé JavaLorsque vous ajoutez le
synchronized
mot - clé à une méthode statique, la méthode ne peut être appelée que par un seul thread à la fois.Dans votre cas, chaque appel de méthode:
SessionFactory
Session
Cependant, voici vos exigences:
getObjectById
être appelé pour toutes les classes lorsqu'il est appelé par une classe particulièreAinsi, même si la
getObjectById
méthode est thread-safe, l'implémentation est incorrecte.SessionFactory
les meilleures pratiquesLe
SessionFactory
est thread-safe, et c'est un objet très coûteux à créer car il doit analyser les classes d'entité et construire la représentation du métamodèle d'entité interne.Donc, vous ne devriez pas créer le
SessionFactory
à chaquegetObjectById
appel de méthode.Au lieu de cela, vous devez créer une instance singleton pour elle.
Le
Session
devrait toujours être ferméVous n'avez pas fermé le
Session
dans unfinally
bloc, ce qui peut entraîner une fuite des ressources de la base de données si une exception est levée lors du chargement de l'entité.Selon la
Session.load
méthode, JavaDoc peut lancer unHibernateException
si l'entité est introuvable dans la base de données.C'est pourquoi vous devez utiliser un
finally
bloc pour fermer leSession
, comme ceci:Empêcher l'accès multi-thread
Dans votre cas, vous vouliez vous assurer qu'un seul thread ait accès à cette entité particulière.
Mais le
synchronized
mot - clé empêche seulement deux threads d'appelergetObjectById
simultanément. Si les deux threads appellent cette méthode l'un après l'autre, vous aurez toujours deux threads utilisant cette entité.Ainsi, si vous souhaitez verrouiller un objet de base de données donné afin qu'aucun autre thread ne puisse le modifier, vous devez utiliser des verrous de base de données.
Le
synchronized
mot-clé ne fonctionne que dans une seule JVM. Si vous disposez de plusieurs nœuds Web, cela n'empêchera pas l'accès multi-thread sur plusieurs JVM.Ce que vous devez faire est d'utiliser
LockModeType.PESSIMISTIC_READ
ouLockModeType.PESSIMISTIC_WRITE
lors de l'application des modifications à la base de données, comme ceci:Alors, voici ce que j'ai fait:
EntityTransaction
et commencé une nouvelle transaction de base de donnéesPost
entité tout en maintenant un verrou sur l'enregistrement de base de données associéPost
entité et commis la transactionException
rejet, j'ai annulé la transactionla source