Vorwort
Jeder, der mit der gleichzeitigen Programmierung von Java vertraut ist, weiß, dass die Ereignisregel (HB) in JMM (Java-Speichermodell), das die Ordnung und Sichtbarkeit von Java-Multi-Thread-Operationen definiert, und die Auswirkungen der Zusammenstellung von Compiler auf Programmergebnisse verhindert.
Es gibt eine Regel von "When vor" in der Java -Sprache. Es handelt sich um eine teilweise Reihenfolge zwischen zwei im Java -Speichermodell definierten Operationen. Wenn der Betrieb A in Betrieb B zuerst erfolgt, bedeutet dies, dass vor Operation B der Einfluss von Betrieb A durch Operation B beobachtet werden kann. Der "Einfluss" umfasst das Ändern des Werts gemeinsamer Variablen im Speicher, das Senden von Nachrichten, die Aufrufmethoden usw., was im Grunde nichts mit der Abfolge des Auftretens rechtzeitig zu tun hat. Dieses Prinzip ist besonders wichtig. Es ist die Hauptgrundlage, um zu beurteilen, ob Daten in Bezug auf Daten konkurrieren und ob Threads sicher sind.
Nach der offiziellen Erklärung:
Wenn eine Variable von mehreren Threads gelesen und von mindestens einem Thread geschrieben wird, treten keine HB -Beziehung zwischen Lese- und Schreibvorgängen auf, Datenrennprobleme.
Um sicherzustellen, dass der Thread, der B betreibt, das Ergebnis von Operation A sieht (unabhängig davon, ob A und B im selben Thread sind), muss das HB -Prinzip zwischen A und B erfüllt werden, und wenn nicht, kann dies zur Neuordnung führen.
Wenn die HB -Beziehung fehlt, kann es zu Neuordnungsproblemen kommen.
Was sind die Regeln für HB?
Jeder ist damit sehr vertraut. Die meisten Bücher und Artikel werden eingeführt. Lassen Sie es uns kurz hier überprüfen:
Unter ihnen habe ich die Lieferregeln, was von entscheidender Bedeutung ist, fett gemacht. So verwenden Sie die Bereitstellungsregeln kompetent zum Schlüssel zur Erreichung der Synchronisation.
Erläutern Sie dann HB aus einer anderen Perspektive: Wenn eine Operation A HB B betreibt, ist das Betriebsergebnis von Operation A auf der gemeinsam genutzten Variablen für Operation B sichtbar
Gleichzeitig ist das Betriebsergebnis von Operation A auf der gemeinsam genutzten Variablen für den Betrieb B für Operation B.
Das Prinzip der Sichtbarkeit ist das Cache -Protokoll und die Speicherbarriere. Die Sichtbarkeit wird durch Cache -Kohärenzprotokolle und Gedächtnisbarrieren erreicht.
Wie kann man Synchronisation erreichen?
In Doug Leas Buch "Java Concurrency in Practice" lautet die folgende Beschreibung:
Das Buch erwähnt: Durch die Kombination einiger HB -Regeln kann die Sichtbarkeit einer entsperrten geschützten Variablen erreicht werden.
Da diese Technik jedoch empfindlich auf die Reihenfolge der Aussagen ist, ist sie anfällig für Fehler.
Als nächstes zeigt der Autor, wie eine Variable durch volatile Regeln und Programmreihenregeln synchronisiert werden kann.
Lassen Sie uns ein vertrautes Beispiel haben:
Klasse Threadprintdemo {static int num = 0; statische flüchtige Boolesche Flagge = Falsch; public static void main (String [] args) {Thread t1 = neuer Thread (() -> {für (; 100> num;) {if (! Flag && (num == 0 || ++ num % 2 == 0)) {System.out.println (num); Flag = true;}}}}); Thread t2 = neuer Thread (() -> {für (; 100> num;) {if (flag && (++ num % 2! = 0)) {System.out.println (num); Flag = false;}}}); t1.start (); t2.Start (); }}Der Zweck dieses Codes besteht darin, die Nummern 0 - 100 zwischen zwei Threads auszudrucken.
Schüler, die mit gleichzeitiger Programmierung vertraut sind, müssen sagen, dass diese Num -Variable nicht volatil verwendet wird, und es wird Sichtbarkeitsprobleme geben, dh der T1 -Thread hat die NUM aktualisiert, und der T2 -Thread kann ihn nicht wahrnehmen.
Haha, der Autor dachte das zu Beginn, aber kürzlich stellte ich durch das Studium der HB -Regeln fest, dass es in Ordnung ist, die flüchtige Modifikation von NUM zu entfernen.
Lassen Sie es uns analysieren und das Poster hat ein Bild gezeichnet:
Lassen Sie uns diese Abbildung analysieren:
Hinweis: Die HB -Regel stellt sicher, dass die Ergebnisse des vorherigen Vorgangs für den nächsten Vorgang sichtbar sind.
Daher ist sich im obigen Applet Thread B der Modifikation von Num durch Thread A voll bewusst, auch wenn Num nicht mit flüchtigem modifiziert ist.
Auf diese Weise verwenden wir das HB-Prinzip, um den synchronen Betrieb einer Variablen zu realisieren, dh in einer Umgebung mit mehreren Threads gewährleisten wir die Sicherheit der gleichzeitigen Änderung gemeinsamer Variablen. Und es gibt keine Java -Primitiven für diese Variable: flüchtig und synchronisiert und CAS (vorausgesetzt, sie zählt).
Dies mag unsicher erscheinen (eigentlich sicher) und scheint nicht leicht zu verstehen. Denn all dies wird durch das Cache -Protokoll und die Speicherbarriere in der zugrunde liegenden HB implementiert.
Andere Regeln, um Synchronisation zu erreichen
Implementierung unter Verwendung von Thread -Kündigungsregeln:
statische int a = 1; public static void main (string [] args) {thread tb = neuer Thread (() -> {a = 2;}); Thread ta = neuer Thread (() -> {try {tb.join ();} catch (interruptedException e) {// no} system.out.println (a);}); ta.start (); tb.start (); } Verwenden Sie Thread Start -Regeln, um zu implementieren:
statische int a = 1; public static void main (string [] args) {thread tb = neuer Thread (() -> {System.out.println (a);}); Thread ta = neuer Thread (() -> {tb.start (); a = 2;}); ta.start (); }Diese beiden Vorgänge können auch die Sichtbarkeit der Variablen a sicherstellen.
Es untergräbt das vorherige Konzept wirklich. Wenn eine Variable im vorherigen Konzept nicht durch volatile oder endgültige Änderungen geändert wird, ist das Lesen und Schreiben unter Multi -Threading definitiv unsicher - da es Caches geben wird, was dazu führt, dass das Lesen nicht das neueste ist.
Durch die Verwendung von HB können wir es jedoch erreichen.
Zusammenfassen
Obwohl der Titel dieses Artikels darin besteht, synchrone Operationen gemeinsamer Variablen durch Ereignis zu realisieren, besteht der Hauptzweck darin, vor Ort zu verstehen, bevor sie tiefer genauer sind. Das Verständnis seines Ereigniskonzepts besteht darin, die Ordnung des vorherigen Betriebs für den nächsten Betrieb zu gewährleisten, und die Sichtbarkeit des Betriebs führt zu einer Umgebung mit mehreren Threaden.
Gleichzeitig können zwei Threads synchronisiert werden, indem sie transitive Regeln flexibel verwenden und dann Regeln kombinieren. Die Implementierung der angegebenen gemeinsam genutzten Variablen ohne Verwendung von Primitiven kann ebenfalls die Sichtbarkeit sicherstellen. Obwohl dies nicht sehr leicht zu lesen scheint, ist es auch ein Versuch.
Doug Lea praktiziert in JUC, wie Regeln kombiniert werden können, um die Synchronisation zu erreichen.
Zum Beispiel die Innenklasse -Synchronisierung der alten Version von Futuretask (verschwunden), die flüchtige Variable durch die tryReleaseshared -Methode und Tryacquireshared die flüchtige Variable liest, die die flüchtigen Regeln verwendet.
Dies nutzt die Programmreihenregeln, indem sie vor TryReleaseshared und dann nach Tryacquireshared eine nichtflüchtige Ergebnisvariable festgelegt und dann die Ergebnisvariable lesen.
Dies gewährleistet die Sichtbarkeit der Ergebnisvariablen. Ähnlich wie bei unserem ersten Beispiel: Verwenden von Programmreihenregeln und volatilen Regeln, um eine normale variable Sichtbarkeit zu erreichen.
Doug Lea selbst sagte, dass diese "Verwendung von Hilfe" -Technologie sehr anfällig für Fehler ist und mit Vorsicht verwendet werden sollte. In einigen Fällen ist diese Art von "Hebel" jedoch sehr vernünftig.
In der Tat "benutzte" Blockingqueue auch als Regeln. Erinnerst du dich an die Entsperrenregel? Beim Einschalten müssen die internen Elemente sichtbar sein.
Es gibt andere Operationen in der Klassenbibliothek, die auch das vorgefertigte Prinzip "verwenden": gleichzeitige Container, Countdownlatch, Semaphor, Zukunft, Testamentsvollstrecker, Cyclicbarrier, Austauscher usw.
Kurz gesagt, kurz: Kurz gesagt:
Das vorgeschlagene Prinzip ist der Kern von JMM. Nur wenn das HB -Prinzip erfüllt ist, kann sie bestellen und die Sichtbarkeit gewährleistet werden, andernfalls wird der Compiler den Code überarbeitet. HB definiert sogar die Regeln für Sperre und Flüchtigkeit.
Durch angemessene Kombination von HB -Regeln kann die korrekte Verwendung ordentlicher gemeinsamer Variablen erreicht werden.
Okay, das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.