java.util.concurrent
L'API fournit une classe appelée as Lock
, qui sérialiserait essentiellement le contrôle afin d'accéder à la ressource critique. Il donne des méthodes telles que park()
et unpark()
.
Nous pouvons faire des choses similaires si nous pouvons utiliser des synchronized
mots clés wait()
et des notify() notifyAll()
méthodes et des utilisations .
Je me demande lequel d'entre eux est le meilleur dans la pratique et pourquoi?
Réponses:
Si vous verrouillez simplement un objet, je préférerais utiliser
synchronized
Exemple:
Vous devez le faire explicitement
try{} finally{}
partout.Alors qu'avec synchronisé, c'est super clair et impossible de se tromper:
Cela dit, les
Lock
s peuvent être plus utiles pour des choses plus compliquées où vous ne pouvez pas acquérir et publier de manière aussi propre. Je préférerais honnêtement éviter d'utiliser des bareLock
s en premier lieu, et opter pour un contrôle de concurrence plus sophistiqué tel que aCyclicBarrier
ou aLinkedBlockingQueue
, s'ils répondent à vos besoins.Je n'ai jamais eu de raison d'utiliser
wait()
ounotify()
mais il peut y en avoir de bonnes.la source
std::lock_guard
J'ai trouvé que
Lock
etCondition
(et d'autres nouvellesconcurrent
classes) ne sont que des outils supplémentaires pour la boîte à outils. Je pouvais faire presque tout ce dont j'avais besoin avec mon ancien marteau à griffes (lesynchronized
mot - clé), mais il était difficile à utiliser dans certaines situations. Plusieurs de ces situations délicates sont devenues beaucoup plus simples une fois que j'ai ajouté plus d'outils à ma boîte à outils: un maillet en caoutchouc, un marteau à boule, un levier et des poinçons. Cependant , mon vieux marteau à griffes voit toujours sa part d'utilisation.Je ne pense pas que l'un soit vraiment «meilleur» que l'autre, mais chacun convient mieux à différents problèmes. En un mot, le modèle simple et la nature orientée portée de
synchronized
me protègent des bogues dans mon code, mais ces mêmes avantages sont parfois des obstacles dans des scénarios plus complexes. Ce sont ces scénarios plus complexes que le package simultané a été créé pour aider à résoudre. Mais l'utilisation de ces constructions de niveau supérieur nécessite une gestion plus explicite et prudente du code.===
Je pense que JavaDoc fait un bon travail pour décrire la distinction entre
Lock
etsynchronized
(l'accent est mis sur moi):la source
Vous pouvez obtenir tout ce que les services publics en java.util.concurrent font avec les primitives de bas niveau comme
synchronized
,volatile
ou attente / avisezCependant, la concurrence est délicate et la plupart des gens se trompent au moins en partie, ce qui rend leur code incorrect ou inefficace (ou les deux).
L'API simultanée fournit une approche de plus haut niveau, qui est plus facile (et en tant que telle plus sûre) à utiliser. En un mot, vous ne devriez plus avoir besoin d'utiliser
synchronized, volatile, wait, notify
directement.La classe Lock elle-même se trouve sur le côté inférieur de cette boîte à outils, vous n'aurez peut-être même pas besoin de l'utiliser directement (vous pouvez utiliser
Queues
et Semaphore et d'autres choses, etc., la plupart du temps).la source
java.util.concurrent
est plus facile [en général] que les fonctionnalités du langage (synchronized
, etc ...). Lorsque vous utilisez,java.util.concurrent
vous devez prendre l'habitude de terminerlock.lock(); try { ... } finally { lock.unlock() }
avant d'écrire du code, alors qu'avec un,synchronized
vous êtes fondamentalement bien dès le début. Sur cette seule base, je dirais quesynchronized
c'est plus facile (étant donné que vous voulez son comportement) quejava.util.concurrent.locks.Lock
. par 4Il existe 4 facteurs principaux expliquant pourquoi vous voudriez utiliser
synchronized
oujava.util.concurrent.Lock
.Remarque: le verrouillage synchronisé est ce que je veux dire lorsque je parle de verrouillage intrinsèque.
Lorsque Java 5 est sorti avec ReentrantLocks, ils se sont avérés avoir une différence de débit assez remarquable par rapport au verrouillage intrinsèque. Si vous recherchez un mécanisme de verrouillage plus rapide et que vous utilisez la version 1.5, pensez à jucReentrantLock. Le verrouillage intrinsèque de Java 6 est désormais comparable.
jucLock a différents mécanismes de verrouillage. Verrouillage interruptible - essayez de verrouiller jusqu'à ce que le fil de verrouillage soit interrompu; verrouillage chronométré - essayez de verrouiller pendant un certain temps et abandonnez si vous ne réussissez pas; tryLock - tente de verrouiller, si un autre thread tient le verrou abandonner. Tout cela est inclus à part la simple serrure. Le verrouillage intrinsèque n'offre qu'un verrouillage simple
la source
Je voudrais ajouter quelques éléments en plus de la réponse de Bert F.
Locks
prend en charge diverses méthodes pour un contrôle de verrouillage plus fin, qui sont plus expressifs que les moniteurs implicites (synchronized
verrous)Avantages du verrouillage sur la synchronisation à partir de la page de documentation
L'utilisation de méthodes ou d'instructions synchronisées permet d'accéder au verrou implicite du moniteur associé à chaque objet, mais oblige toutes les acquisitions et libérations de verrous à se produire de manière structurée par blocs
Les implémentations de verrouillage fournissent des fonctionnalités supplémentaires par rapport à l'utilisation de méthodes et d'instructions synchronisées en fournissant une tentative non bloquante d'acquérir un
lock (tryLock())
, une tentative d'acquérir le verrou qui peut être interrompu (lockInterruptibly()
et une tentative d'acquérir le verrou qui peuttimeout (tryLock(long, TimeUnit))
.Une classe Lock peut également fournir un comportement et une sémantique assez différents de ceux du verrouillage implicite du moniteur, comme l' ordre garanti, l'utilisation non réentrante ou la détection de blocage.
ReentrantLock : En termes simples, selon ma compréhension,
ReentrantLock
permet à un objet de rentrer d'une section critique à une autre section critique. Puisque vous avez déjà verrouillé pour entrer dans une section critique, vous pouvez une autre section critique sur le même objet en utilisant le verrou actuel.ReentrantLock
caractéristiques clés selon cet articleVous pouvez utiliser
ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
pour acquérir davantage de contrôle sur le verrouillage granulaire sur les opérations de lecture et d'écriture.En dehors de ces trois ReentrantLocks, java 8 fournit un autre Lock
StampedLock:
Vous pouvez utiliser ces tampons pour libérer un verrou ou pour vérifier si le verrou est toujours valide. De plus, les verrous estampés prennent en charge un autre mode de verrouillage appelé verrouillage optimiste.
Jetez un œil à cet article sur l'utilisation de différents types de verrous
ReentrantLock
etStampedLock
.la source
La principale différence est l'équité, en d'autres termes, les demandes sont-elles traitées FIFO ou peut-il y avoir des barges? La synchronisation au niveau de la méthode garantit une allocation équitable ou FIFO du verrou. En utilisant
ou
n'assure pas l'équité.
Si vous avez beaucoup de conflits pour le verrou, vous pouvez facilement rencontrer des barges où les demandes plus récentes obtiennent le verrou et les demandes plus anciennes restent bloquées. J'ai vu des cas où 200 threads arrivent en peu de temps pour un verrou et le deuxième à arriver a été traité en dernier. C'est correct pour certaines applications, mais pour d'autres, c'est mortel.
Voir le livre "Java Concurrency In Practice" de Brian Goetz, section 13.3 pour une discussion complète de ce sujet.
la source
Le livre "Java Concurrency In Practice" de Brian Goetz, section 13.3: "... Comme le ReentrantLock par défaut, le verrouillage intrinsèque n'offre aucune garantie d'équité déterministe, mais les garanties d'équité statistique de la plupart des implémentations de verrouillage sont assez bonnes pour presque toutes les situations ..."
la source
Lock facilite la vie des programmeurs. Voici quelques situations qui peuvent être réalisées facilement avec la serrure.
Alors que, le verrou et les conditions reposent sur le mécanisme synchronisé. Par conséquent, peut certainement être en mesure d'obtenir les mêmes fonctionnalités que vous pouvez obtenir en utilisant le verrou. Cependant, la résolution de scénarios complexes avec synchronisé peut vous rendre la vie difficile et vous empêcher de résoudre le problème réel.
la source
Différence majeure entre verrou et synchronisé:
la source
Verrouiller et synchroniser le bloc ont tous deux le même objectif, mais cela dépend de l'utilisation. Considérez la partie ci-dessous
Dans le cas ci-dessus, si un thread entre dans le bloc de synchronisation, l'autre bloc est également verrouillé. S'il existe plusieurs blocs de synchronisation de ce type sur le même objet, tous les blocs sont verrouillés. Dans de telles situations, java.util.concurrent.Lock peut être utilisé pour empêcher le verrouillage indésirable des blocs
la source