Bei der Programmierung mit mehreren Threads sollte das kritischste und betroffenste Problem das Problem der Synchronisation sein, was ein schwieriger Punkt und der Kern darstellt.
Von der synchronisierten und volatilen Version der frühesten Version von JDK bis zur Sperrgrenze in der Java.util.Concurrent.locks-Paket in JDK 1.5 (die Implementierungen umfassen Readlock, Writelock und Reentrantlock), ist die Multi-Threading-Implementierung ebenfalls nach und nach verärgert.
Welchen Mechanismus wird zur Steuerung der Synchronisation verwendet? Die erste Reaktion ist die Verriegelung, die beim Erlernen des Betriebssystems und der Datenbank hätte ausgesetzt sein müssen. In Java-Multi-Thread-Programmen wird der erste Thread, der auf die Ressource zugreift, eine Objektsperrung zugewiesen, wenn mehrere Programme um dieselbe Ressource konkurrieren, um eine Ressourcenkorrosion zu verhindern, und die späteren Generationen müssen auf die Freigabe dieser Objektschloss warten.
Ja, das Besorgteste an der Synchronisation von Java -Threads ist die Verwendung gemeinsamer Ressourcen.
Lassen Sie uns zunächst einige gemeinsame Ressourcen verstehen, von denen Threads verfügbar sind.
Aus der JVM müssen wir die von Threads gemeinsam genutzten Daten koordinieren:
1. Die im Haufen gespeicherte Instanzvariable; 2. Die Klassenvariable, die im Methodenbereich gespeichert ist.
Wenn die virtuelle Java -Maschine eine Klasse lädt, wird jedes Objekt oder jede Klasse einem Monitor zugeordnet, um die Instanzvariable oder Klassenvariable des Objekts zu schützen. Wenn das Objekt keine Instanzvariablen hat oder die Klasse keine Variablen hat, überwacht der Monitor nichts.
Um den oben genannten Mutex der oben genannten Monitore zu erreichen, verbindet die virtuelle Maschine ein Schloss (auch als unsichtbares Schloss bezeichnet) für jedes Objekt oder jede Klasse. Lassen Sie mich hier erklären, dass Klassensperrungen auch über Objektsperren implementiert werden, da die JVM beim Laden der Klasse eine Instanz von Java.lang.class für jede Klasse erstellt. Wenn das Schloss gegen ein Objekt ist, ist das Klassenobjekt dieser Klasse gesperrt.
Zusätzlich kann ein Thread ein Objekt mehrmals sperren, was mehreren Veröffentlichungen entspricht. Es handelt sich um einen von JVM für jede Objektschloss bereitgestellten Sperrrechner. Das letzte Schloss wird 1 hinzugefügt und der entsprechende Minus 1 und wenn der Rechnerwert 0 ist, wird er freigegeben. Diese Objektschloss wird vom Monitor innerhalb des JVM verwendet und wird auch automatisch vom JVM generiert. Alle Programmierer müssen es nicht selbst hinzufügen.
Nachdem wir das Synchronisationsprinzip von Java eingeführt haben, werden wir zum Thema gelangen und zuerst über die Verwendung von Synchronisierungen sprechen. Weitere Synchronisierungen werden in den folgenden Kapiteln eingeführt.
Versuchen wir zuerst ein Beispiel ausführen.
Paket Thread_test; / *** Testen Sie Multithread -Programme, mit denen die Implementierung der Thread -Klasse erweitert wird. public testthread (int threadnum) {this.threadnum = threadnum; } @Override public synchronisierte void run () {für (int i = 0; i <1000; i ++) {System.out.println ("Nr." + Threadnum + ":" + i); }} public static void main (String [] args) löst eine Ausnahme aus {für (int i = 0; i <10; i ++) {new TestThread (i) .Start (); Thread.Sleep (1); }}}
Auslaufergebnisse:
Nr. 0: 887 Nr. 0: 888 Nr. 0: 889 Nr. 0: 890 Nr. 0: 891 Nr. 0: 892 Nr. 0: 893 Nr. 0: 894 Nr. 7: 122 Nr. 7: 123 Nr. 7: 124
Das obige ist nur ein Clip, der ein Problem erklärt.
Wenn Sie vorsichtig sind, werden Sie feststellen, dass Nr. 0: 894 Nr. 7: 122 folgt, was bedeutet, dass es nicht von 0 bis 999 beginnt.
Es wird gesagt, dass synchronisierte Synchronisationsmethoden oder Synchronisationsblöcke implementieren können. Warum kann es hier nicht funktionieren?
Lassen Sie uns zunächst den Synchronisationsmechanismus analysieren. Die Synchronisation wird durch Sperren erreicht. Welches Objekt ist also im obigen Beispiel gesperrt oder welche Klasse ist gesperrt? Es gibt zwei Variablen im Inneren, einer ist i und der andere ist Threadnum; Ich bin intern für die Methode und Threadnum ist privat.
Lassen Sie uns den laufenden Mechanismus von synchronisiert kennenlernen:
In einem Java -Programm wird dieser Bereich für die Überwachung markiert, wenn synchronisierte Block- oder synchronisierte Methoden verwendet werden. Wenn ein JVM das Programm behandelt und ein Programm in den Überwachungsbereich eintritt, sperrt es das Objekt oder die Klasse automatisch.
Was ist also im obigen Beispiel gesperrt, nachdem das synchronisierte Schlüsselwort verwendet wurde?
Beim synchronisierten Methode sperren Sie das Instanzobjekt, das die Methode selbst als Objektsperrung aufruft. In diesem Beispiel haben die 10 Threads ihre eigenen Objekte für TestThread -Klassen, sodass das erworbene Objektschloss auch eine eigene Objektschloss ist und nichts mit anderen Threads zu tun hat.
Um die Verriegelung von Methoden zu implementieren, müssen freigegebene Objekte gesperrt werden.
Ändern Sie das obige Beispiel und schauen Sie sich dann an:
Paket Thread_test; / *** Testen Sie Multithread -Programme, mit denen die Implementierung der Thread -Klasse erweitert wird. private String -Flag; // public testthread (int threadnum, String flag) {this.threadnum = threadnum; this.flag = Flag; } @Override public void run () {synchronized (flag) {für (int i = 0; i <1000; i ++) {System.out.println ("no." + Threadnum + ":" + i); }}} public static void main (String [] args) löst Ausnahme aus {String flag = new String ("Flag"); für (int i = 0; i <10; i ++) {new testthread (i, flag) .Start (); Thread.Sleep (1); }}}
Dies wird auch eine gemeinsame Flagge hinzugefügt. Anschließend wird das Flaggenflag über den synchronisierten Block synchronisiert; Dies entspricht den Bedingungen für die Verriegelung des gemeinsam genutzten Objekts.
Ja, die laufenden Ergebnisse sind in Ordnung.
Geben Sie durch den synchronisierten Block die Erfassung von Objektsperrungen an, um die Synchronisation zu erreichen. Gibt es also andere Methoden, die durch die synchronisierte Methode implementiert werden können?
Nach dem Prinzip der Synchronisation: Wenn eine gemeinsame Objektsperrung oder eine Klassenschloss erhalten werden kann, kann eine Synchronisation erreicht werden. Können wir es also erreichen, indem wir ein Klassenschloss teilen?
Ja, wir können statische Synchronisationsmethoden verwenden. Nach den Eigenschaften statischer Methoden ermöglicht es nur das Klassenobjekt selbst aufgerufen und kann nicht durch Instanziierung eines Klassenobjekts aufgerufen werden. Wenn Sie dann die Sperre dieser statischen Methode erhalten, erhalten Sie die Klassenschloss, und diese Klassenschloss ist alle Testthread -Klassenschlösser, und der Zweck der Erhalt der gemeinsam genutzten Klassenschlösser wird erreicht.
Der Implementierungscode lautet wie folgt:
Paket Thread_test; / ** * Testen Sie Multi-Thread-Programme, die die Implementierung der Thread-Klasse erweitern. public testthread (int threadnum) {this.threadnum = threadnum; } public static synchronisierte void statictest (int threadnum) {für (int i = 0; i <1000; i ++) {System.out.println ("no." + threadnum + ":" + i); }} public static void main (String [] args) löst eine Ausnahme aus {für (int i = 0; i <10; i ++) {new TestThread (i) .Start (); Thread.Sleep (1); }} @Override public void run () {statictest (threadnum); }} Das Laufergebnis ist weggelassen, das gleiche wie im zweiten Beispiel.
Der obige Inhalt erklärt hauptsächlich zwei Probleme: Synchronisationsblöcke und Synchronisationsmethoden.
1. Synchronisierter Block: Die erfasste Objektsperrung ist die Flag -Objektsperrung in synchronisiertem (Flag).
2. Synchronisationsmethode: Das Klassenobjekt, zu dem die Methode gehört, und die Klassenobjektsperrung.
Die statische Synchronisationsmethode wird definitiv synchronisiert, da mehrere Threads gemeinsam genutzt werden.
Anstelle statischer Synchronisationsmethoden werden sie nur im Singleton -Modus synchronisiert.