J'essaie de comprendre ce qui rend le verrouillage de la concurrence si important si l'on peut l'utiliser synchronized (this)
. Dans le code factice ci-dessous, je peux faire soit:
- synchronisé la méthode entière ou synchroniser la zone vulnérable (
synchronized(this){...}
) - OU verrouillez la zone de code vulnérable avec un ReentrantLock.
Code:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
synchronized(this){synchronized(this){//some code}}
ne causera donc pas de blocage. Pour le verrouillage intrinsèque s'ils obtiennent un moniteur sur une ressource et s'ils le veulent à nouveau, ils peuvent l'obtenir sans verrou mort.Réponses:
Un ReentrantLock n'est pas structuré , contrairement aux
synchronized
constructions - c'est-à-dire que vous n'avez pas besoin d'utiliser une structure de bloc pour le verrouillage et pouvez même maintenir un verrou entre les méthodes. Un exemple:Un tel flux est impossible à représenter via un seul moniteur dans une
synchronized
construction.En plus de cela,
ReentrantLock
prend en charge l' interrogation des verrous et les attentes de verrouillage interruptibles qui prennent en charge le délai d'attente .ReentrantLock
prend également en charge la politique d' équité configurable , permettant une planification plus flexible des threads.ReentrantLock
peut également être plus évolutif , offrant de bien meilleures performances en cas de conflit élevé. Vous pouvez en savoir plus à ce sujet ici .Cette allégation a cependant été contestée; voir le commentaire suivant:
Quand faut-il utiliser
ReentrantLock
s? Selon cet article de developerWorks ...la source
ReentrantLockPseudoRandom
code dans le lien Lycog utilise de nouveaux verrous incontrôlés à chaque appel desetSeed
andnext
ReentrantReadWriteLock
est une serrure spécialisée alors qu'ellesynchronized(this)
est une serrure à usage général. Ils sont similaires mais pas tout à fait les mêmes.Vous avez raison en ce que vous pourriez utiliser à la
synchronized(this)
place deReentrantReadWriteLock
mais l'inverse n'est pas toujours vrai.Si vous souhaitez mieux comprendre ce qui rend la
ReentrantReadWriteLock
recherche spéciale, des informations sur la synchronisation des threads producteur-consommateur.En général, vous vous souvenez que la synchronisation de méthode entière et la synchronisation à usage général (en utilisant le
synchronized
mot - clé) peuvent être utilisées dans la plupart des applications sans trop réfléchir à la sémantique de la synchronisation, mais si vous avez besoin d'extraire les performances de votre code, vous devrez peut-être explorer d'autres mécanismes de synchronisation plus fins ou à usage spécial.Soit dit en passant, l'utilisation
synchronized(this)
- et en général le verrouillage à l'aide d'une instance de classe publique - peut être problématique car elle ouvre votre code à des verrous mortels potentiels parce que quelqu'un d'autre, sans le savoir, pourrait essayer de se verrouiller contre votre objet ailleurs dans le programme.la source
public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
Depuis la page de documentation d' Oracle sur ReentrantLock :
Un ReentrantLock appartient au dernier thread verrouillé avec succès, mais ne le déverrouille pas encore. Un thread invoquant un verrou reviendra, acquérant avec succès le verrou, lorsque le verrou n'appartient pas à un autre thread. La méthode retournera immédiatement si le thread actuel possède déjà le verrou.
Le constructeur de cette classe accepte un paramètre d' équité facultatif . Lorsqu'ils sont définis sur true, en cas de conflit, les verrous favorisent l'octroi de l'accès au thread le plus long . Sinon, ce verrou ne garantit aucun ordre d'accès particulier.
Fonctionnalités clés de ReentrantLock selon cet article
Vous pouvez utiliser ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock pour acquérir davantage de contrôle sur le verrouillage granulaire des opérations de lecture et d'écriture.
Jetez un œil à cet article de Benjamen sur l'utilisation de différents types de ReentrantLocks
la source
Vous pouvez utiliser des verrous réentrants avec une politique d'équité ou un délai d'expiration pour éviter la famine des threads. Vous pouvez appliquer une politique d'équité des threads. cela aidera à éviter qu'un thread n'attende éternellement pour accéder à vos ressources.
La "politique d'équité" sélectionne le prochain thread exécutable à exécuter. Il est basé sur la priorité, le temps écoulé depuis la dernière exécution, bla bla
aussi, Synchronize peut bloquer indéfiniment s'il ne peut pas échapper au bloc. Reentrantlock peut avoir un délai d'expiration défini.
la source
Les verrous synchronisés n'offrent aucun mécanisme de file d'attente dans lequel, après l'exécution d'un thread, n'importe quel thread exécuté en parallèle peut acquérir le verrou. En raison de quoi le thread qui est là dans le système et qui fonctionne pendant une plus longue période de temps n'a jamais la chance d'accéder à la ressource partagée conduisant ainsi à la famine.
Les verrous réentrants sont très flexibles et ont une politique d'équité dans laquelle si un thread attend plus longtemps et après l'achèvement du thread en cours d'exécution, nous pouvons nous assurer que le thread en attente plus long a la possibilité d'accéder à la ressource partagée en diminuant ainsi le débit du système et en le rendant plus long.
la source
Supposons que ce code s'exécute dans un thread:
Parce que le thread possède le verrou, il autorisera plusieurs appels à verrouiller (), donc il ré-entrera dans le verrou. Cela peut être réalisé avec un décompte de référence afin qu'il n'ait pas à acquérir à nouveau le verrouillage.
la source
Une chose à garder à l'esprit est:
le nom « ReentrantLock » donne un mauvais message sur les autres mécanismes de verrouillage qu'ils ne sont pas rentrants. Ce n'est pas vrai. Le verrou acquis via «synchronisé» est également ré-entrant en Java.
La principale différence est que «synchronisé» utilise un verrouillage intrinsèque (celui que possède chaque objet), contrairement à l'API de verrouillage.
la source
Je pense que les méthodes wait / notify / notifyAll n'appartiennent pas à la classe Object car elles polluent tous les objets avec des méthodes rarement utilisées. Ils ont beaucoup plus de sens sur une classe Lock dédiée. Donc, de ce point de vue, il est peut-être préférable d'utiliser un outil qui est explicitement conçu pour le travail à accomplir - c'est-à-dire ReentrantLock.
la source