Cet article analyse les concepts, les principes et l'utilisation des opérations cas dans la programmation Java à travers des exemples. Il a une certaine valeur de référence et les amis dans le besoin peuvent en apprendre davantage.
CAS fait référence à une instruction spéciale largement prise en charge par les processeurs modernes qui fonctionne sur des données partagées en mémoire. Cette instruction effectue des opérations de lecture et d'écriture atomiques sur les données partagées en mémoire.
Une brève introduction au processus de fonctionnement de cette instruction : Tout d'abord, le CPU compare les données à modifier dans la mémoire avec la valeur attendue. Ensuite, lorsque les deux valeurs sont égales, le CPU remplace la valeur en mémoire par la nouvelle valeur. Dans le cas contraire, aucune opération ne sera effectuée. Enfin, le CPU renvoie l'ancienne valeur. Cette série d'opérations est atomique. Bien qu'ils semblent compliqués, ils constituent la raison fondamentale pour laquelle le mécanisme de concurrence Java 5 est meilleur que le mécanisme de verrouillage d'origine. En termes simples, la signification de CAS est "Qu'est-ce que je pense que la valeur d'origine devrait être, si c'est le cas, mettez à jour la valeur d'origine avec la nouvelle valeur, sinon ne la modifiez pas et dites-moi quelle est la valeur d'origine." (Cette description est tirée de "Java Concurrent Programming Practice")
Pour faire simple, CAS a 3 opérandes, la valeur mémoire V, l'ancienne valeur attendue A et la nouvelle valeur à modifier B. Si et seulement si la valeur attendue A et la valeur mémoire V sont identiques, modifiez la valeur mémoire V en B, sinon renvoyez V. C'est une idée de verrouillage optimiste.Il croit qu'aucun autre thread ne le modifiera avant qu'il ne soit modifié;Synchronisé est un verrou pessimiste.Il croit que d'autres threads le modifieront avant qu'il ne soit modifié.Efficacité du verrouillage pessimisteTrès faible.
Regardons un exemple simple :
if(a==b) { a++; }
Imaginez simplement que se passerait-il si la valeur de a était modifiée avant de faire a++ ? Est-ce que a++ est toujours exécuté ? La raison de ce problème est que dans un environnement multithread, la valeur de a est dans un état incertain. Les verrous peuvent résoudre de tels problèmes, mais CAS peut également les résoudre sans verrous.
int expect = a; if(a.compareAndSet(expect,a+1)) { doSomeThing1(); } else { doSomeThing2(); }
De cette façon, a++ ne sera pas exécuté si la valeur de a est modifiée.
Selon la méthode d'écriture ci-dessus, après a!=expect, a++ ne sera pas exécuté. Et si nous voulons toujours effectuer une opération a++, cela n'a pas d'importance. 🎜>
while(true) { int expect = a; if (a.compareAndSet(expect, a + 1)) { doSomeThing1(); return; } else { doSomeThing2(); } }En utilisant la méthode d'écriture ci-dessus, une opération a++ est implémentée sans verrouillage. Il s'agit en fait d'un algorithme non bloquant.
Application
Presque la plupart des classes du package java.util.concurrent.atomic utilisent des opérations CAS, prenez AtomicInteger comme exemple, voir Look lors de l'implémentation de plusieurs de ses méthodes principales :public final int getAndSet(int newValue) { for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } }L'explication dans la documentation JDK de la méthode getAndSet est la suivante : définir une valeur donnée de manière atomique et renvoyer l'ancienne valeur. Là où la méthode atomique est reflétée, elle est reflétée dans compareAndSet. Voyons comment compareAndSet est implémenté :
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }Comme prévu, il utilise la classe Unsafe. L'opération CAS est complété.
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }C'est presque exactement la même chose que l'exemple original, et utilise également l'opération CAS pour implémenter l'opération d'incrémentation automatique.
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }De plus, java.util .concurrent. La classe ConcurrentLinkedQueue utilise un algorithme non bloquant, qui n'utilise aucun verrou, et est entièrement implémenté sur la base d'opérations CAS. Le fonctionnement CAS peut être considéré comme le fondement du cadre de concurrence JAVA, et la conception de l'ensemble du cadre est basée sur le fonctionnement CAS.
Inconvénients :
Résumé
CAS peut être utilisé pour implémenter des opérations atomiques sans verrous, mais les scénarios d'application doivent être clairement définis. Pour des opérations très simples sans introduire de verrous, vous pouvez envisager d'utiliser des opérations CAS lorsque vous souhaitez réaliser une opération. fonctionnement non bloquant. Il n'est pas recommandé d'introduire CAS dans des opérations complexes, car cela rendrait le programme moins lisible et difficile à tester, et des problèmes ABA surviendraient.
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!