Comprendre CAS et AQS en un seul article

Multithreading JAVA, quelque chose que les interviewers aiment demander

Quelques trucs conceptuels

L'atomicité signifie que l'opération est indivisible. Que ce soit multicœur ou monocœur, une quantité atomique, un seul thread peut y opérer à la fois. En bref, les opérations qui ne sont pas interrompues par le planificateur de thread pendant toute l'opération peuvent être considérées comme atomiques. Par exemple, a = 1;

Non-atomicité: Cela signifie que le planificateur de thread interrompra l'opération pendant tout le processus. Les opérations
telles que "a ++" ne sont pas atomiques, car elles peuvent devoir passer par les deux étapes suivantes:

(1) Prendre la valeur d'un

(2) Calculer a + 1

S'il y a deux threads t1, t2 exécute de telles opérations. Après la première étape, t1 a été interrompu par l'ordonnanceur de threads avant qu'il n'ait eu le temps d'ajouter 1, donc t2 a commencé à s'exécuter. Après l'exécution de t2, t1 a commencé à exécuter la deuxième étape (à ce moment, la valeur de a dans t1 peut être toujours l'ancienne valeur, ce n'est pas certain, cela n'apparaîtra que si la valeur de a dans le thread t2 n'est pas mise à jour à t1 à temps). Une erreur s'est produite à ce moment et le fonctionnement de t2 équivaut à être ignoré

Planification des threads JAVA - planification préemptive (priorité)


CAS— (Compare And Swap) compare et échange

Adoptez une pensée de verrouillage optimiste - pensez toujours que vous pouvez terminer l'opération

Lorsque plusieurs threads manipulent une variable, un seul thread sera mis à jour avec succès, les autres échouent et le thread ayant échoué est autorisé à réessayer

CAS spin en attente

Verrouille ou synchronizedpeut être réalisé une opération atomique de mot-clé, alors pourquoi utiliser CAS, car les performances de verrouillage ou de mot-clé synchronisé ont entraîné une grande perte, mais avec le verrouillage optimiste CAS peut être obtenu, il s'agit en fait de l'utilisation directe des instructions de niveau CPU, donc les performances est très élevé.

Alors, comment CAS réalise-t-il le verrouillage du spin? CAS utilise des instructions du CPU pour assurer l'atomicité de l'opération pour obtenir l'effet de verrouillage. Quant au spin, il est généralement réalisé avec une boucle infinie. De cette façon, dans une boucle infinie, une opération CAS est exécutée. Lorsque l'opération réussit et renvoie true, la boucle se termine; lorsqu'elle renvoie false, la boucle continue et l'opération CAS continue d'être tentée jusqu'à ce qu'elle renvoie true.

Entrez le code source CAS pour voir
import java.util.concurrent.atomic.AtomicInteger;

Définissez atomiquement la valeur sur la valeur mise à jour donnée ( update), si la valeur actuelle est égale à la valeur attendue ( expect). Renvoie true, met à jour la valeur de la variable, la valeur réelle n'est pas égale à la valeur attendue, renvoie false, le thread ne fait rien, CAS renvoie la valeur de la variable courante;

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

À l'intérieur, unsafe.compareAndSwapInt(this, valueOffset, expect, update);il y a une nativeméthode, utilisant l'implémentation c ++, sont intéressés peuvent aller voir les fichiers de code source safe.cpp JDK, CAS fonctionne directement avec le système d'exploitation;

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
Problème ABA causé par CAS

Qu'est-ce que l'ABA?

Je peux savoir d'après ce qui précède qu'il existe une prémisse importante pour la mise en œuvre de l'algorithme CAS: vous devez retirer les données à un certain moment de la mémoire, puis les comparer et les remplacer au moment suivant. À ce décalage horaire , les données peuvent avoir changé, ce qui conduit au problème ABA;

Solution: une partie est résolue en ajoutant le numéro de version (version),

AQS est un synchroniseur de file d'attente abstrait

AQS maintient un état de variable de ressource partagée avec une sémantique volatile (prenant en charge la visibilité sous plusieurs threads) et une file d'attente de thread FIFO (lorsque l'état de la concurrence multithread est bloqué, il entre dans cette file d'attente). java.util.concurrent.locks.AbstractQueuedSynchronizerClasse abstraite, appelée AQS

img

La façon dont AQS partage les ressources: exclusives et partagées

AQS fournit deux modes: le mode exclusif et le mode partagé par défaut, et l'implémentation correspondante de JDK a ReentrantLocketReentrantReadWriteLock

Exclusif: un seul thread peut s'exécuter, l'implémentation JAVA spécifique a ReentrantLock

Partagé: plusieurs threads s'exécutent en même temps

AQS est implémenté sur la base de volitale et CAS. Un état de variable de type valitale est maintenu dans AQS pour
faire un nombre réentrant de verrous réentrants. Le verrouillage et la libération des verrous sont également effectués autour de cette variable.

Insérez la description de l'image ici

Analyse AQS recommandée


Je suppose que tu aimes

Origine blog.csdn.net/weixin_44313584/article/details/114695205
conseillé
Classement