Vor dem Lesen dieses Artikels können Sie zunächst " Einführung und Nutzung des Java -Multithread -Atomic -Pakets " lesen, um sich über den relevanten Inhalt des Atompakets zu informieren.
1. Was ist Atomic?
Das Wort Atomic hat etwas mit Atomen zu tun, das einst als die Einheit der kleinsten Materie angesehen wurde. Atomic in einem Computer bedeutet, dass es nicht in mehrere Teile unterteilt werden kann. Wenn ein Stück Code als atomar angesehen wird, bedeutet dies, dass der Code während der Ausführung nicht unterbrochen werden kann. Im Allgemeinen werden Atomanweisungen von Hardware bereitgestellt und von Software zur Implementierung von Atommethoden bereitgestellt (ein Thread wird nach Abschluss seiner Ausführung erst nach Abschluss der Methode unterbrochen).
Auf der X86 -Plattform bietet die CPU die Möglichkeit, den Bus während der Anweisungsausführung zu sperren. Auf dem CPU -Chip gibt es ein Lead #Hlockpin. Wenn das Präfix "Sperre" zu einer Anweisung im Assembler -Sprachprogramm hinzugefügt wird, wird der CPU des Montagemaschinens bei der Ausführung dieser Anweisung das Potenzial von #Hlockpin verringern und diese bis zum Ende dieser Anweisung freigeben, wodurch der Bus sperrt. Auf diese Weise kann ein anderer CPUs im selben Bus vorerst über den Bus nicht zugreifen, um die Atomizität dieser Anweisung in einer Multiprozessorumgebung zu gewährleisten.
2. Atomvariablen in Java.util.Concurrent
Ob direkt oder indirekt, fast alle Klassen im java.util.concurrent -Paket verwenden Atomvariablen, nicht die Synchronisation. Klassen wie ConcurrentLinkedQueue verwenden auch Atomvariablen, um den Wartefreiheitalgorithmus direkt zu implementieren, während Klassen wie Concurrenthashmap Reentrantlock bei Bedarf zum Sperren verwenden. Reentrantlock verwendet dann Atomvariablen, um die Thread -Warteschlange aufzubewahren, die auf das Sperren wartet.
Ohne JVM-Verbesserungen in JDK5.0 werden diese Klassen nicht konstruiert, die (der Klassenbibliothek, nicht der Benutzerklasse) Schnittstellen aussetzen, um Synchronisation-Primitive auf Hardwareebene zuzugreifen. Die Atomvariablenklassen und andere Klassen in java.util.concurrent geben diese Funktionen der Benutzerklasse aus
Atomklasse von Java.util.Concurrent.atomic
Dieses Paket bietet eine Reihe von Atomklassen. Seine grundlegende Funktion ist, dass in einer Umgebung, wenn mehrere Threads in den Instanzen dieser Klassen gleichzeitig enthalten sind, exklusiv, dh wenn ein Thread die Methode eingibt und die Anweisungen darin ausführt, wird es nicht von anderen Threads unterbrochen, und andere Threads sind wie Spin-Schlösser. Bis die Methode ausgeführt wird, wählt der JVM einen anderen Thread aus der gewarteten Warteschlange aus. Dies ist nur ein logisches Verständnis. Tatsächlich wird es mit Hilfe relevanter Hardwareanweisungen implementiert und blockiert keine Threads (oder es wird nur auf Hardwareebene blockiert). Die Klassen können in 4 Gruppen unterteilt werden
Atomicboolean, Atomicinger, Atomiclong, Atomicreference
Atomicintegerarray, Atomiclongarray
Atomiclongfieldupdater, Atomicingerfieldupdater, Atomicreferencefieldupdater
AtomicmarkableReference, AtomicStampedReference, Atomicreferencearray
Unter ihnen sind Atomicboolean, Atomicinder, Atomiclong, Atomicreference ähnlich.
Zunächst einmal sind Atomicboolean, Atomicinteger, Atomiclong, Atomicreference interne APIs ähnlich: Nehmen Sie ein Beispiel für Atomicreference
Erstellen Sie einen fadenfesten Stapel mit Atomicreference
öffentliche Klasse LinkedStack <T> {private atomicreference <node <t >> stacks = new atomicreference <node <t >> (); public t push (t e) {node <t> altennode, newnode; Während (wahr) {// Die Verarbeitung hier ist etwas ganz Besonderes und muss der Fall sein. oldNode = stacks.get (); newnode = new node <t> (e, OldNode); if (stacks.compareAnDSet (OldNode, NewNode)) {return e;}}} public t pop () {node <t> oldnode, newnode; while (wahr) {udnode = stacks (); (Stacks.CompareAnDSet (OldNode, NewNode)) {return OldNode.Object;}}} private statische endgültige Klassenknoten <T> {private t -Objekt; privater Knoten <T> Weiter; privater Knoten (t Objekt, Knoten <T> Weiter) {this.object = Object; this.next = Weiter;Konzentrieren Sie sich dann auf das Atom -Update des Feldes.
Atomicintegerfieldupdater <t>/atomiclongfieldupdater <t>/atomicreferencefieldupdater <t, v> ist der Wert eines Feldes, das auf Reflexion basiert.
Die entsprechende API ist ebenfalls sehr einfach, hat aber auch einige Einschränkungen.
(1) Das Feld muss vom Typ flüchtig sein! Was ist volatil? Bitte überprüfen Sie " detaillierte Erläuterung der volatilen Schlüsselwörter in Java "
(2) Der Beschreibungstyp des Feldes (Modifikator öffentlich/geschützt/Standard/privat) steht im Einklang mit der Beziehung zwischen dem Anrufer und dem Feld Operation Object. Das heißt, der Anrufer kann das Objektfeld direkt bedienen und dann atomare Operationen reflektieren und ausführen. Für die Felder der übergeordneten Klasse kann die Unterklasse jedoch nicht direkt betrieben werden, obwohl die Unterklasse auf die Felder der übergeordneten Klasse zugreifen kann.
(3) Es kann nur eine Instanzvariable sein, nicht eine Klassenvariable, dh es kann keine statischen Schlüsselwörter hinzufügen.
(4) Es kann nur modifizierte Variablen und nicht zu endgültigen Variablen verarbeitet werden, da die Semantik der Finale nicht modifiziert ist. Tatsächlich können die Semantik des endgültigen und volatilen Konflikts und diese beiden Schlüsselwörter nicht gleichzeitig existieren.
(5) Für Atomicingerfieldupdater und AtomiclongfieldUpdater können sie nur Felder des int/langen Typs modifizieren und ihren Wrapper -Typ (ganzzahl/lang) nicht ändern. Wenn Sie den Wraping -Typ ändern möchten, müssen Sie AtomicreferenceFieldUpdater verwenden.
Die Betriebsmethode wird im folgenden Beispiel beschrieben.
import Java.util.concurrent Fieldname) {return atomicingerfieldupdater.newupdater (Demodata.Class, FieldName);} void doit () {Demodata data = new Demodata (); System.out.println ("1 ==>"+getupdater ("Value1"). getandset (Data, 10); "+getupdater (" value2 "). IncrementandGet (Daten)); System.out.println (" 2 ==> "+getupdater (" value3 "). {Atomicintegerfieldupdaterdemo Demo = New AtomicintergerfieldUpdaterdemo (); Demo.doit ();}}Im obigen Beispiel ist der Feldwert3/value4 von Demodata nicht für die Atomicintegerfieldupdaterdemo -Klasse sichtbar, sodass sein Wert nicht direkt durch Reflexion geändert werden kann.
Ein von der AtomicmarkableReferenference -Klasse beschriebenes Paar von boolean> kann den Wert von Objekt oder Booleschen atomisch ändern. Diese Datenstruktur ist in einigen Cache- oder Zustandsbeschreibungen nützlicher. Diese Struktur kann den Durchsatz effektiv verbessern, wenn Objekt/Boolesche einzeln oder gleichzeitig geändert werden.
Die AtomicStampedReference -Klasse verwaltet Objektreferenzen mit Ganzzahl "Flags" und kann atomisch aktualisiert werden. Im Vergleich zum <Objekt, boolean> der AtomicmarkableReenference -Klasse, behält AtomicStampedReference eine Datenstruktur bei, die <Objekt int> ähnelt, die tatsächlich eine gleichzeitige Anzahl von Objekten ist (Referenzen). Im Gegensatz zu Atomicinderer kann diese Datenstruktur jedoch eine Objektreferenz tragen und gleichzeitig atomare Operationen für dieses Objekt ausführen und zählen.
"ABA -Problem" wird am Ende dieses Artikels erwähnt, und AtomicmarkableReference/AtomicStampedReference ist nützlich bei der Lösung von "ABA -Problem".
III. Die Rolle der Atomar
Dadurch können der Betrieb einzelner Daten atomisiert werden
Erstellen Sie einen komplexen, blockierfreien Code mit Atomkursen
Es wird allgemein angesehen, dass 2 oder mehr Atomvariablen (oder 2 oder mehr Vorgänge in einer einzelnen Atomvariablen durchführen) eine Synchronisation erfordern, damit diese Vorgänge als Atomeinheit verwendet werden können.
Kein Sperrung und kein Wartenalgorithmus
Parallelitätsalgorithmen basierend auf CAS (Vergleichswap) werden als lock-freie Algorithmen bezeichnet, da Threads nicht mehr auf das Sperren warten müssen (manchmal als Mutexes oder kritische Teile bezeichnet, abhängig von der Terminologie der Thread-Plattform). Unabhängig davon, ob der CAS -Vorgang erfolgreich ist oder fehlschlägt, wird sie in beiden Fällen innerhalb einer vorhersehbaren Zeit abgeschlossen. Wenn CAS ausfällt, kann der Anrufer den CAS -Betrieb wiederholen oder andere geeignete Operationen nehmen.
Wenn jeder Thread weiter funktioniert, wenn andere Fäden verzögert (oder sogar fehlgeschlagen sind), kann gesagt werden, dass der Algorithmus wartfrei ist. Im Gegensatz dazu erfordert der lockfreie Algorithmus, dass nur ein bestimmter Faden den Vorgang immer durchführt. (Eine weitere Definition von keiner Wartezeit besteht darin, sicherzustellen, dass jeder Thread in seinen begrenzten Schritten seine eigenen Operationen korrekt berechnet, unabhängig von den Vorgängen, dem Zeitpunkt, dem Übergang oder der Geschwindigkeit anderer Threads. Diese Grenze kann eine Funktion der Anzahl der Threads im System sein. Zum Beispiel, wenn 10 Fäden jeweils jeweils 10 Fäden ausführen. Wenn Sie das Schlimmste bis hin zu einem Thread, werden Sie jeweils ein.
In den letzten 15 Jahren haben die Menschen umfangreiche Untersuchungen zu warten-freien und lockfreien Algorithmen (auch als nicht blockierende Algorithmen bezeichnet) durchgeführt, und viele Menschen haben nicht blockierende Algorithmen in allgemeinen Datenstrukturen entdeckt. Nicht blockierende Algorithmen werden in Betriebssystem und JVM-Ebene häufig verwendet, wobei Aufgaben wie Threading und Prozessplanung ausgeführt werden. Obwohl ihre Implementierung komplexer ist, haben sie viele Vorteile gegenüber schlossbasierten alternativen Algorithmen: Sie können Gefahren wie Prioritätsinversion und Deadlock, der Wettbewerb, billiger, die Koordination auf einer feineren Granularitätsniveau ermöglicht, die ein höheres Maß an Parallelität und so weiter ermöglicht.
Gemeinsam:
Nicht blockierender Zähler
Nicht blockierender Stapel gleichzeitiger Stack
Nicht blockierende verknüpfte Liste Concurrent LinkedQueue
ABA Fragen:
Denn vor dem Wechseln von V fragt die CAS hauptsächlich "ob der Wert von V noch ein" ist ", bevor V, bevor V zum ersten Mal gelesen wird und CAS-Operationen auf V durchführt, wird der Wert von A nach B und dann zurück zu A den CAS-basierten Algorithmus verwirren. In diesem Fall wird die CAS -Operation erfolgreich sein, aber in einigen Fällen ist das Ergebnis möglicherweise nicht das, was Sie erwartet haben. Diese Art von Problem wird als ABA -Problem bezeichnet, das normalerweise durch Zusammenarbeit mit einem Tag oder einer Versionsnummer mit jedem Wert der CAS -Operation und der ordnungsgemäßen Aktualisierung der Werte und Tags behandelt wird. Die AtomicStampedReference -Klasse unterstützt diese Methode.
Zusammenfassen
Das obige ist die detaillierte Erklärung dieses Artikels zu operativen Atomvariablen und Atomklassen im Java-Multi-Thread-Atompaket. Ich hoffe, es wird für alle hilfreich sein. Interessierte Freunde können weiterhin auf diese Seite verweisen:
Java-Programmierung: Multi-Thread-Deadlock und Kommunikation zwischen Threads sind einfacher Code
Java Multi-Thread-Programmierung kleines Beispiel simuliert das Parkplatzsystem
Eine kurze Diskussion über die Vorteile und Code -Beispiele von Java Multithreading
Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen.