1. Scénarios applicables pour CAS et synchronisé
1. Pour les situations où la concurrence des ressources est moindre, en utilisant le verrouillage synchronisé synchronisé pour le blocage des threads et les opérations de commutation et de commutation de réveil entre les noyaux utilisateur est un gaspillage supplémentaire de ressources CPU; Bien que le CAS soit implémenté en fonction du matériel, il n'a pas besoin de saisir le noyau, n'a pas besoin de changer de threads, et le risque de spin d'exploitation est moindre, de sorte que des performances plus élevées peuvent être obtenues.
2. En cas de concurrence grave des ressources, la probabilité de spin CAS est relativement élevée, gaspillant ainsi plus de ressources CPU et étant moins efficace que synchronisée. En prenant la classe AtomicInteger dans le package java.util.concurrent.atomic à titre d'exemple, sa méthode getandincrement () est implémentée comme suit:
public final int getAndIncrement () {for (;;) {int courant = get (); int next = courant + 1; if (comparabledset (courant, suivant)) Retour courant; }}Si la méthode ComparandDset (Current, Next) est exécutée avec succès, elle sera renvoyée directement; Si la compétition de thread est féroce, ce qui entraîne la méthode de comparaison (courant, suivant) qui ne peut pas être exécutée avec succès, il sera bouclé et attendu que la tranche de temps allouée par le processeur au fil soit épuisée, réduisant ainsi considérablement l'efficacité.
2. Scénarios d'utilisation d'erreur CAS
classe publique Casdemo {private final int thread_num = 1000; Final privé int max_value = 20000000; ATOMICITEGER ATOMICEGER PRIVÉ = NOUVEAU ATOMICILETER (0); private int synci = 0; String privé Path = "/ Users / Pingping / Datacenter / Books / Linux / Linux Commands.txt"; public void Casadd () lève InterruptedException {long début = System.CurrentTimeMillis (); Thread [] threads = nouveau thread [thread_num]; pour (int i = 0; i <thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getAndinCment ();}}}); Threads [i] .start (); } pour (int j = 0; j <thread_num; j ++) {threads [j] .join (); } System.out.println ("CAS coûte du temps:" + (System.Currenttimemillis () - Begin)); } public void syncadd () lève InterruptedException {long begin = system.currentTimemillis (); Thread [] threads = nouveau thread [thread_num]; for (int i = 0; i <thread_num; i ++) {Threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronisé ("synci") {++ synci;}}}}}); Threads [i] .start (); } pour (int j = 0; j <thread_num; j ++) threads [j] .join (); System.out.println ("Sync coûte du temps:" + (System.CurrentTimemillis () - Begin)); }}En fonctionnant sur mon CPU à double noyau, le résultat est le suivant:
On peut voir que sous différents fils, le temps passé à utiliser le calcul CAS est bien plus que celui de synchronisé. La raison en est la ligne 15
14 while (casi.get () <max_value) {15 casi.getandincrement (); 16}L'opération est une opération très longue. Une fois que 15 lignes sont exécutées, la boucle sera immédiatement entrée et l'exécution se poursuivra, entraînant de graves conflits de fil.
3. Scénarios d'utilisation des CAS améliorés
Afin de résoudre le problème ci-dessus, il est nécessaire de faire plus longtemps le temps d'exécution de chaque boucle, c'est-à-dire qu'il peut considérablement réduire les conflits de threads. Modifiez le code comme suit:
classe publique Casdemo {private final int thread_num = 1000; Final privé int max_value = 1000; ATOMICITEGER ATOMICEGER PRIVÉ = NOUVEAU ATOMICILETER (0); private int synci = 0; String privé Path = "/ Users / Pingping / Datacenter / Books / Linux / Linux Commands Communs Explication détaillée.txt"; public void Casadd2 () lève InterruptedException {long begin = System.currenttimemillis (); Thread [] threads = nouveau thread [thread_num]; pour (int i = 0; i <thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getandinCment (); try (inputStream in = new FileInputStream (new File (path)) {while while (in.Read ()! = -} cord (IoException e) {e.printStackTrace ();}}}}}); Threads [i] .start (); } pour (int j = 0; j <thread_num; j ++) threads [j] .join (); System.out.println ("Cas Random Cost Time:" + (System.CurrentTimemillis () - Begin)); } public void syncadd2 () lève InterruptedException {long begin = system.currenttimemillis (); Thread [] threads = nouveau thread [thread_num]; pour (int i = 0; i <thread_num; i ++) {threads [i] = new Thread (new Runnable () {public void run () {while (synci <max_value) {synchronisé ("synci") {++ synci;} try (inputStream in = new FileInStream (new File (path } catch (ioException e) {e.printStackTrace ();}}}); Threads [i] .start (); } pour (int j = 0; j <thread_num; j ++) threads [j] .join (); System.out.println ("Sync coûte du temps:" + (System.CurrentTimemillis () - Begin)); }}Dans la boucle while, une opération pour lire le contenu du fichier est ajoutée, ce qui prend environ 40 ms, réduisant ainsi les conflits de threads. Les résultats des tests sont les suivants:
On peut voir que lorsque les conflits des ressources sont relativement petits, la méthode CAS et l'efficacité de synchronisation synchronisée sont similaires. Pourquoi les CAS n'atteignent-ils pas des performances plus élevées que la synchronisée?
Le JDK utilisé dans le test est de 1,7. À partir de JDK1.6, de nombreuses optimisations ont été introduites à la mise en œuvre de verrous, tels que le grossissement des verrous, l'élimination des verrous, le verrouillage léger, le verrouillage biaisé, le filage adaptatif et d'autres technologies pour réduire les frais généraux de l'opération de verrouillage. Le principe du verrouillage de spin est similaire à CAS Spin, et est encore plus optimisé que le spin CAS. Pour plus de détails, veuillez consulter le mécanisme de verrouillage JVM en profondeur 1 synchronisé.
4. Résumé
1. Lorsque vous utilisez CAS, lorsque les conflits de fil sont graves, les performances du programme seront considérablement réduites; CAS convient uniquement aux situations où il y a moins de conflits de fil.
2. Synchronisé a été amélioré et optimisé après JDK1.6. L'implémentation sous-jacente de synchronisée repose principalement sur la file d'attente sans serrure. L'idée de base est de bloquer après la rotation, de continuer à rivaliser pour les verrous après le changement de compétition, de sacrifier légèrement l'équité, mais d'obtenir un débit élevé. Lorsqu'il y a moins de conflits de fil, des performances similaires peuvent être obtenues; Lorsqu'il y a de sérieux conflits de fil, les performances sont beaucoup plus élevées que celles des CAS.
Le résumé ci-dessus de la programmation simultanée Java - Utilisation de Cas Carely est l'explication détaillée de l'éditeur. J'espère que cela pourra vous donner une référence et j'espère que vous pourrez soutenir Wulin.com plus.