1. Anwendbare Szenarien für CAS und Synchronisierte
1. In Situationen, in denen der Ressourcenwettbewerb geringer ist, ist die Verwendung der synchronisierten Synchronisationsschloss für das Blockieren von Thread-Blockierungen und das Weckschalt- und Switching-Vorgänge zwischen den Benutzer-Zustand-Kernel eine zusätzliche Verschwendung von CPU-Ressourcen. Während CAS basierend auf Hardware implementiert ist, muss nicht in den Kernel gelangen, muss keine Threads wechseln, und die Wahrscheinlichkeit eines Betriebs von Spin ist geringer, sodass eine höhere Leistung erzielt werden kann.
2. Im Falle eines schwerwiegenden Ressourcenwettbewerbs ist die Wahrscheinlichkeit eines CAS -Spin relativ hoch, wodurch mehr CPU -Ressourcen verschwendet und weniger effizient als synchronisiert ist. Nehmen Sie die Atomicinteger -Klasse in der Java.util.Concurrent.atomic Paket als Beispiel für die Methode von GetAndIncrement () wie folgt implementiert:
public Final int getAndIncrement () {for (;;) {int current = get (); int next = current + 1; if (vergleicheSet (aktuell, nächst) zurücksend; }}Wenn die Vergleichs -Methode (aktuell, nächst) erfolgreich ausgeführt wird, wird sie direkt zurückgegeben. Wenn der Thread -Wettbewerb heftig ist, was zu der Vergleichsset (aktuell, nächster) Methode führt, die nicht erfolgreich ausgeführt werden kann, wird er bis zum Zeitpunkt der CPU, die dem Faden zugeteilt wird, geschoben und gewartet, wodurch die Effizienz stark verringert wird.
2. CAS -Fehlerverbrauchszenarien
öffentliche Klasse Casdemo {private final int thread_num = 1000; private endgültige int max_value = 20000000; private atomicinteger casi = neuer atomicinteger (0); private int synci = 0; private String path = "/user/pingping/Datacenter/books/linux/linux Common -Befehle.txt"; public void casadd () löst InterruptedException {long begin = system.currentTimemillis () aus; Thread [] threads = neuer Thread [Thread_num]; für (int i = 0; i <thread_num; i ++) {threads [i] = neuer Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getandIncrement ();}}); Themen [i] .Start (); } für (int j = 0; j <thread_num; j ++) {threads [j] .Join (); } System.out.println ("CAS kostet Zeit:" + (System.currentTimemillis () - Beginn)); } public void syncadd () löscht InterruptedException {long begin = system.currentTimemillis (); Thread [] threads = neuer Thread [Thread_num]; für (int i = 0; i <thread_num; i ++) {threads [i] = neuer thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;}}}}}); Themen [i] .Start (); } für (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("Synchronisation kostet die Zeit:" + (System.currentTimemillis () - begin)); }}Wenn Sie auf meiner Doppelkern -CPU ausgeführt werden, ist das Ergebnis wie folgt:
Es ist ersichtlich, dass unter verschiedenen Threads die Zeit, die die CAS -Berechnung verwendet hat, viel mehr als die von synchronisiert ist. Der Grund ist Zeile 15
14 while (casi.get () <max_value) {15 casi.getandIncrement (); 16}Der Betrieb ist ein sehr zeitaufwändiger Betrieb. Nach 15 Zeilen wird die Schleife sofort eingegeben und die Ausführung wird fortgesetzt, was zu schwerwiegenden Fadenkonflikten führt.
3. Verbesserte CAS -Nutzungsszenarien
Um das obige Problem zu lösen, ist es nur notwendig, die Ausführungszeit jeder Schleife länger zu gestalten, dh es kann Fadenkonflikte erheblich reduzieren. Ändern Sie den Code wie folgt:
öffentliche Klasse Casdemo {private final int thread_num = 1000; private endgültige int max_value = 1000; private atomicinteger casi = neuer atomicinteger (0); private int synci = 0; private String path = "/user/pingping/datacenter/books/linux/linux Common -Befehle detaillierte Erläuterung.txt"; public void casadd2 () löst InterruptedException {long begin = system.currentTimemillis () aus; Thread [] threads = neuer Thread [Thread_num]; für (int i = 0; i <thread_num; i ++) {threads [i] = neuer Thread (new Runnable () {public void run () {while (casi.get () <max_value) {casi.getandIncrement (); try (InputStream in = new FileInputStream (new Datei) {path) {WHOW) {WHOW) {WHOW (IN.); (IoException e) {e.printstacktrace ();}}}}}); Themen [i] .Start (); } für (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("cas random kostet die Zeit:" + (System.currentTimemillis () - begin)); } public void syncadd2 () löscht InterruptedException {long begin = system.currentTimemillis (); Thread [] threads = neuer Thread [Thread_num]; für (int i = 0; i <thread_num; i ++) {threads [i] = neuer Thread (new Runnable () {public void run () {while (synci <max_value) {synchronized ("synci") {++ synci;} try (Input -Stream in = -Anneue). } catch (ioException e) {e.printstacktrace ();}}}}); Themen [i] .Start (); } für (int j = 0; j <thread_num; j ++) threads [j] .Join (); System.out.println ("Synchronisation kostet die Zeit:" + (System.currentTimemillis () - begin)); }}In der while -Schleife wird eine Operation zum Lesen des Dateiinhalts hinzugefügt, der etwa 40 ms dauert, wodurch Thread -Konflikte reduziert werden. Die Testergebnisse sind wie folgt:
Es ist ersichtlich, dass die CAS -Methode und die synchronisierte Synchronisationseffizienz ähnlich sind, wenn Ressourcenkonflikte relativ gering sind. Warum erreicht CAS keine höhere Leistung als synchronisiert?
Der im Test verwendete JDK ist 1,7. Ausgehend von JDK1.6 wurden viele Optimierungen zur Implementierung von Schlössern wie Vergröberung, Verriegelungseliminierung, leichter Verriegelung, vorgespannter Verriegelung, adaptives Spinning und anderen Technologien eingeführt, um den Overhead des Sperrbetriebs zu verringern. Das Prinzip des Spin -Locks ähnelt Cas Spin und ist noch optimierter als Cas -Spin. Weitere Informationen finden Sie im ausführlichen JVM-Sperrmechanismus von 1-synchronisiert.
4. Zusammenfassung
1. Bei der Verwendung von CAS wird die Programmleistung, wenn Fadenkonflikte schwerwiegend sind, stark reduziert. CAS ist nur für Situationen geeignet, in denen weniger Fadenkonflikte vorhanden sind.
2. Synchronisiert wurde nach JDK1.6 verbessert und optimiert. Die zugrunde liegende Implementierung von Synchronisierten hängt hauptsächlich auf der Warteschlange der lock-freien ab. Die Grundidee besteht darin, nach dem Spin zu blockieren, nach dem Wechsel des Wettbewerbs weiterhin um Schlösser zu kämpfen, die Fairness leicht zu opfern, aber einen hohen Durchsatz erhalten. Wenn weniger Fadenkonflikte vorhanden sind, kann eine ähnliche Leistung erzielt werden. Wenn es ernsthafte Fadenkonflikte gibt, ist die Leistung viel höher als die von CAS.
Die obige Zusammenfassung der gleichzeitigen Programmierung von Java - sorgfältig verwendet CAS die detaillierte Erklärung des Herausgebers. Ich hoffe, es kann Ihnen eine Referenz geben und ich hoffe, Sie können Wulin.com mehr unterstützen.