Optimisation du verrouillage
L'optimisation du verrouillage fait ici principalement référence à l'optimisation de la synchronisation par JVM.
Verrouillage rotatif
La synchronisation mutex dans l'état de blocage est très coûteuse et doit être évitée autant que possible. Dans de nombreuses applications, les données partagées ne sont verrouillées que pendant une courte période. L'idée d'un verrou tournant est de permettre à un thread d'effectuer une boucle occupée (spin) pendant un certain temps lors d'une demande de verrouillage de données partagées. Si le verrou peut être obtenu pendant cette période, il peut éviter d'entrer dans l'état de blocage. .
Bien que le verrouillage rotatif puisse éviter d'entrer dans un état de blocage et réduire la surcharge, il nécessite une opération de boucle occupée pour occuper le temps CPU. Il ne convient que pour les scénarios dans lesquels l'état de verrouillage des données partagées est très court.
Les verrous tournants adaptatifs ont été introduits dans JDK 1.6. Adaptatif signifie que le nombre de tours n'est plus fixe, mais est déterminé par le nombre précédent de tours sur la même serrure et le statut du propriétaire de la serrure.
Suppression du verrouillage
L'élimination des verrous fait référence à l'élimination des verrous sur les données partagées qui sont détectées comme étant peu susceptibles d'avoir une concurrence.
L'élimination des verrous est principalement prise en charge via l'analyse d'échappement. Si les données partagées sur le tas ne peuvent pas s'échapper et être accessibles par d'autres threads, elles peuvent alors être traitées comme des données privées et leurs verrous peuvent être éliminés.
Pour certains codes qui ne semblent pas verrouillés, de nombreux verrous sont en fait implicitement ajoutés. Par exemple, le code d'épissage de chaîne suivant ajoute implicitement un verrou :
public static String concatString(String s1, String s2, String s3) { return s1 + s2 + s3 }
; String est une classe immuable et le compilateur optimisera automatiquement l'épissage de String. Avant le JDK 1.5, cela serait converti en une opération append() continue d'un objet StringBuffer :
public static String concatString(String s1, String s2, String s3) { StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s3); ; }
Il existe un bloc de synchronisation dans chaque méthode append(). La machine virtuelle observe la variable sb et découvre rapidement que sa portée dynamique est restreinte à l'intérieur de la méthode concatString(). Autrement dit, toute référence à sb ne s'échappe jamais en dehors de la méthode concatString() et est inaccessible aux autres threads, elle peut donc être éliminée.
Verrouiller la rugosité
Si une série d'opérations consécutives verrouillent et déverrouillent à plusieurs reprises le même objet, des opérations de verrouillage fréquentes entraîneront une perte de performances.
Les méthodes append() consécutives dans l’exemple de code de la section précédente entrent dans cette catégorie. Si la machine virtuelle détecte que le même objet est verrouillé par une telle série d'opérations fragmentées, elle étendra (réduira) la plage de verrouillage à l'extérieur de la séquence d'opérations entière. L'exemple de code de la section précédente est étendu d'avant la première opération append() à après la dernière opération append(), de sorte qu'il ne doit être verrouillé qu'une seule fois.
Serrure légère
JDK 1.6 a introduit les verrous biaisés et les verrous légers, permettant aux verrous d'avoir quatre états : déverrouillé, biaisé, verrouillé léger et verrouillé lourd.
Les verrous lourds sont également communément appelés verrous d'objets synchronisés.
Voici la disposition de la mémoire de l'en-tête de l'objet de la machine virtuelle HotSpot. Ces données sont appelées Mark Word. Les bits de balise correspondent à cinq états, qui sont indiqués dans le tableau des états à droite. En plus de l'état marqué pour gc, les quatre autres états ont été introduits précédemment.
Le côté gauche de la figure ci-dessous est la pile de machine virtuelle d'un thread. Il y a une partie de la zone appelée Lock Record, qui est créée pendant le processus d'exécution du verrouillage léger et est utilisée pour stocker le mot de marque de l'objet de verrouillage. Sur la droite se trouve un objet de verrouillage contenant Mark Word et d'autres informations.
Par rapport aux verrous lourds traditionnels, les verrous légers utilisent les opérations CAS pour éviter la surcharge des verrous lourds utilisant des mutex. Pour la plupart des verrous, il n'y a pas de concurrence pendant tout le cycle de synchronisation, il n'est donc pas nécessaire d'utiliser des mutex pour la synchronisation. Vous pouvez d'abord utiliser les opérations CAS pour la synchronisation. Si CAS échoue, utilisez plutôt des mutex pour la synchronisation.
Lorsque vous essayez d'acquérir un objet verrou, si l'objet verrou est marqué 0 01, cela signifie que l'objet verrou est dans l'état déverrouillé. À ce stade, la machine virtuelle crée un enregistrement de verrouillage dans la pile de machine virtuelle du thread actuel, puis utilise l'opération CAS pour mettre à jour le mot de marque de l'objet vers le pointeur d'enregistrement de verrouillage. Si l'opération CAS réussit, le thread acquiert le verrou sur l'objet et la balise de verrouillage Mark Word de l'objet passe à 00, indiquant que l'objet est dans un état de verrouillage léger.
Si l'opération CAS échoue, la machine virtuelle vérifiera d'abord si le mot de marque de l'objet pointe vers la pile de machine virtuelle du thread actuel. Si tel est le cas, cela signifie que le thread actuel possède déjà l'objet de verrouillage, puis il peut entrer directement dans l'objet de verrouillage. bloc de synchronisation pour continuer l'exécution. Sinon, cela signifie que l'objet verrou a été préempté par d'autres threads. Si plus de deux threads sont en compétition pour le même verrou, le verrou léger n'est plus efficace et doit être étendu en un verrou lourd.
Verrouillage des biais
L'idée du verrouillage biaisé est de privilégier le premier thread à acquérir l'objet verrou. Ce thread n'aura plus besoin d'effectuer d'opérations de synchronisation après l'acquisition du verrou, et même les opérations CAS ne seront plus nécessaires.
Lorsque l'objet verrou est acquis par le thread pour la première fois, il entre dans l'état biaisé et est marqué comme 1 01. Dans le même temps, utilisez l'opération CAS pour enregistrer l'ID du thread dans Mark Word. Si l'opération CAS réussit, ce thread n'aura pas besoin d'effectuer d'opérations de synchronisation à chaque fois qu'il entre dans le bloc de synchronisation lié à ce verrou.
Lorsqu'un autre thread tente d'acquérir cet objet de verrouillage, l'état de biais prend fin. À ce moment, le biais (Revoke Bias) est révoqué et renvoyé à l'état déverrouillé ou à l'état de verrouillage léger.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!