Avant Java 5.0, il n'y avait que des verrous synchronisés (verrous intégrés) et volatiles. Après Java 5.0, le verrou d'affichage ReentrantLock a été introduit.
Présentation de ReentrantLock
ReentrantLock est un verrou réentrant. Il est différent du verrou intégré. Il nécessite un verrouillage et un déverrouillage explicites à chaque utilisation et offre des fonctionnalités plus avancées : verrouillage équitable, verrouillage temporisé, verrouillage conditionnel et verrouillage interrogeable. le verrou. Il peut efficacement éviter le problème de vivacité des implémentations de ReentrantLock.
Interface de verrouillage :
Copiez le code comme suit :
Verrouillage de l'interface publique {
//Bloquer jusqu'à ce que le verrou soit obtenu ou interrompu
verrou vide ();
// Bloquer jusqu'à ce que le verrou soit obtenu ou qu'une exception soit levée lors de l'interruption
void lockInterruptably() lance InterruptedException ;
//Obtenir uniquement lorsque le verrou est disponible, sinon retourner directement
booléen tryLock();
//Obtenez le verrou uniquement s'il est disponible dans le délai spécifié, sinon revenez directement et lancez une exception en cas d'interruption
boolean tryLock (longtemps, unité TimeUnit) lève InterruptedException ;
annuler le déverrouillage ();
//Renvoie une condition liée à ce verrou
Condition newCondition();
}
Utilisation du verrou
Copiez le code comme suit :
Verrouillage = new ReentrantLock();
lock.lock();
essayer{
//mettre à jour le statut de l'objet
}enfin{
//Notez ici qu'il doit y avoir un bloc de code final pour déverrouiller
//Sinon, il est facile de provoquer des blocages et d'autres problèmes d'activité.
lock.unlock();
}
Fonctionnalités de ReentrantLock
Verrous de vote et verrous temporisés
Les demandes de verrouillage interrogeables et chronométrables sont implémentées via la méthode tryLock(), qui est différente de l'acquisition inconditionnelle de verrous. ReentrantLock peut avoir un mécanisme flexible de tolérance aux pannes. De nombreux cas de blocage sont causés par des verrous séquentiels et différents threads tentent d'acquérir. se verrouille. Il se bloque lors du verrouillage et ne libère pas le verrou qu'il détient déjà, provoquant éventuellement un blocage. Lorsque la méthode tryLock() tente d'obtenir un verrou, si le verrou est déjà détenu par un autre thread, elle reviendra immédiatement selon la méthode de réglage au lieu de bloquer et d'attendre. En même temps, elle libérera le verrou qu'elle détient après. retour Vous pouvez le retourner en fonction du retour. En conséquence, une nouvelle tentative ou une annulation est effectuée pour éviter un blocage.
justice
Le constructeur ReentrantLock propose deux options : le verrouillage équitable et le verrouillage injuste (par défaut). Ce qu'on appelle les verrous équitables, les threads acquièrent les verrous dans l'ordre dans lequel ils émettent des requêtes, et le saut de file d'attente n'est pas autorisé, mais pour les verrous injustes, le saut de file d'attente est autorisé : lorsqu'un thread demande d'acquérir un verrou, si le verrou est disponible ; , alors ce thread ignorera le thread en attente dans la file d'attente et acquerra le verrou. Nous souhaitons généralement que tous les verrouillages soient injustes. Parce que lors de l'exécution d'opérations de verrouillage, l'équité réduira considérablement les performances en raison de la surcharge de suspension et de récupération des threads. Considérons une situation : le thread A détient un verrou, le thread B demande le verrou, donc le thread B est suspendu ; lorsque le thread A libère le verrou, le thread B sera réveillé, il essaie donc d'acquérir à nouveau le verrou en même temps, le thread ; C demande également d'acquérir ce verrou, alors le thread C est susceptible d'acquérir, d'utiliser et de libérer ce verrou avant que le thread B ne soit complètement réveillé. Il s'agit d'une situation gagnant-gagnant. Le moment où B acquiert le verrou (B ne peut acquérir le verrou qu'après son réveil) n'est pas retardé. C acquiert le verrou plus tôt et le débit est également amélioré. Dans la plupart des cas, les performances des verrous injustes sont supérieures à celles des verrous équitables.
Les opérations d'acquisition de serrure peuvent être interrompues
La méthode lockInterruptably acquiert le verrou tout en restant sensible aux interruptions, il n'est donc pas nécessaire de créer d'autres types d'opérations de blocage ininterruptibles.
ReadWriteLockReadWriteLock
ReentrantLock est un verrou mutex standard. Un seul thread peut détenir le verrou à la fois. Le verrou en lecture-écriture est différent. Il expose deux objets Lock, dont l'un est utilisé pour les opérations de lecture et l'autre pour les opérations d'écriture.
Copiez le code comme suit :
interface publique ReadWriteLock {
/**
* Renvoie le verrou utilisé pour la lecture.
*
* @renvoie le verrou utilisé pour la lecture.
*/
Verrouiller readLock();
/**
* Renvoie le verrou utilisé pour l'écriture.
*
* @renvoie le verrou utilisé pour l'écriture.
*/
Verrouiller writeLock();
}
Implémentation facultative :
1. Priorité de sortie
2. Lire les sauts de fil en ligne
3. Réentrée
4.Rétrograder
5.Mise à niveau
ReentrantReadWriteLock implémente l'interface ReadWriteLock et le constructeur fournit deux méthodes de création : le verrouillage équitable et le verrouillage injuste. Les verrous en lecture-écriture conviennent aux situations où il y a plus de lecture et moins d'écriture, et peuvent obtenir une meilleure simultanéité.
L'exemple de code de copie est le suivant :
classe publique ReadWriteMap<K, V> {
carte privée Map<K, V> ;
verrou final privé ReadWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public ReadWriteMap(Map<K, V> carte) {
this.map = carte ;
}
public V get (clé K) {
readLock.lock();
essayer {
return map.get(clé);
} enfin {
readLock.unlock();
}
}
public void put (clé K, valeur V) {
writeLock.lock();
essayer {
map.put(clé, valeur);
} enfin {
writeLock.unlock();
}
}
}