Heim >Java >javaLernprogramm >Eine Erklärung der grundlegenden Verwendung des synchronisierten Schlüsselworts in der Java-Multithread-Programmierung
Bei der Multithread-Programmierung sollte die Synchronisierung das kritischste und besorgniserregendste Problem sein. Dies ist ein schwieriger Punkt und der Kern.
Von der Synchronisierung und Volatilität in der frühesten Version von JDK bis zur Lock-Schnittstelle im Paket java.util.concurrent.locks in JDK 1.5 (implementiert mit ReadLock, WriteLock, ReentrantLock) ist auch die Implementierung von Multithreading möglich Reifung Schritt für Schritt Veränderung.
Synchronisierung, durch welchen Mechanismus wird sie gesteuert? Die erste Reaktion sind Sperren. Dem sollten Sie beim Erlernen von Betriebssystemen und Datenbanken ausgesetzt gewesen sein. Wenn in einem Java-Multithread-Programm mehrere Programme um dieselbe Ressource konkurrieren, wird dem ersten Thread eine Objektsperre zugewiesen, um auf die Ressource zuzugreifen, um eine Beschädigung der Ressource zu verhindern, und der nachfolgende Thread muss auf die Freigabe warten Objektsperre.
Ja, bei der Java-Thread-Synchronisierung geht es vor allem um die Nutzung gemeinsam genutzter Ressourcen.
Lassen Sie uns zunächst einige gemeinsame Ressourcen von Threads verstehen.
Verstehen Sie anhand der JVM, welche Threads Daten gemeinsam nutzen, die koordiniert werden müssen:
1. Im Heap gespeicherte Instanzvariablen den Methodenbereich.
Wenn die Java Virtual Machine eine Klasse lädt, wird jedes Objekt oder jede Klasse einem Monitor zugeordnet, um die Instanzvariablen oder Klassenvariablen des Objekts zu schützen, natürlich, wenn das Objekt keine Instanzvariablen oder Klassenvariablen hat Variablen überwacht der Monitor nichts.
Um die oben erwähnte gegenseitige Ausschließlichkeit des Monitors zu erreichen, ordnet die virtuelle Maschine jedem Objekt oder jeder Klasse eine Sperre (auch unsichtbare Sperre genannt) zu Sperren Dies wird dadurch erreicht, dass die JVM beim Laden einer Klasse eine Instanz von java.lang.Class für jede Klasse erstellt. Wenn das Objekt gesperrt ist, ist daher auch das Klassenobjekt dieser Klasse gesperrt.
Darüber hinaus kann ein Thread ein Objekt mehrmals sperren, was mehreren Freigaben entspricht; es handelt sich um einen Sperrrechner, der von der JVM für jede Objektsperre bereitgestellt wird. Die letzte Sperre beträgt 1 , und wenn der Wert des Rechners 0 ist, wird er freigegeben. Diese Objektsperre wird vom Monitor innerhalb der JVM verwendet und automatisch von der JVM generiert. Alle Programmierer müssen sie nicht selbst hinzufügen.
Nachdem wir das Synchronisationsprinzip von Java vorgestellt haben, kommen wir zum Punkt. Lassen Sie uns zunächst über die Verwendung von „Synchronisiert“ sprechen. Weitere Synchronisierungen werden in den folgenden Kapiteln vorgestellt.
Versuchen wir zunächst, ein Beispiel auszuführen.
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * */ public class TestThread extends Thread{ private int threadnum; public TestThread(int threadnum) { this.threadnum = threadnum; } @Override public synchronized void run() { for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } public static void main(String[] args) throws Exception { for(int i=0; i<10; i++){ new TestThread(i).start(); Thread.sleep(1); } } }
Laufergebnisse:
NO.0:887 NO.0:888 NO.0:889 NO.0:890 NO.0:891 NO.0:892 NO.0:893 NO.0:894 NO.7:122 NO.7:123 NO.7:124
Das Obige ist nur ein Ausschnitt zur Veranschaulichung eines Problems.
Aufmerksame Kinder werden feststellen, dass auf NO.0:894 NO.7:122 folgt, was bedeutet, dass es nicht bei 0 bis 999 beginnt.
Es wird gesagt, dass synchronisierte Methoden oder synchronisierte Blöcke implementiert werden können. Warum ist dies hier nicht möglich?
Lassen Sie uns zunächst den Synchronisationsmechanismus analysieren. Welche Objekte oder Klassen werden im obigen Beispiel gesperrt? Es gibt zwei Variablen darin, eine ist i und die andere ist threadnum; i ist in der Methode und threadnum ist privat.
Lassen Sie uns mehr über den synchronisierten Betriebsmechanismus erfahren:
Wenn in einem Java-Programm ein synchronisierter Block oder eine synchronisierte Methode verwendet wird, wird dieser Bereich für die Überwachung markiert, während die JVM das Programm verarbeitet Überwachungsbereich, es Das Objekt oder die Klasse wird automatisch gesperrt.
Was wird also im obigen Beispiel gesperrt, nachdem das synchronisierte Schlüsselwort verwendet wurde?
Wenn eine synchronisierte Methode verwendet wird, wird das Instanzobjekt selbst, das die Methode aufruft, als Objektsperre gesperrt. In diesem Beispiel haben 10 Threads ihre eigenen TestThread-Klassenobjekte, die von ihnen selbst erstellt wurden, sodass die erworbene Objektsperre auch ihre eigene Objektsperre ist und nichts mit anderen Threads zu tun hat.
Um die Methodensperre zu implementieren, muss ein gemeinsam genutztes Objekt gesperrt werden.
Ändern Sie das obige Beispiel und schauen Sie es sich noch einmal an:
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * */ public class TestThread extends Thread{ private int threadnum; private String flag; //标记 public TestThread(int threadnum,String flag) { this.threadnum = threadnum; this.flag = flag; } @Override public void run() { synchronized(flag){ for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } } public static void main(String[] args) throws Exception { String flag = new String("flag"); for(int i=0; i<10; i++){ new TestThread(i,flag).start(); Thread.sleep(1); } } }
Eine gemeinsame Flagge wurde ebenfalls hinzugefügt. Synchronisieren Sie dann das Flag-Flag über den synchronisierten Block. Dies erfüllt die Bedingungen zum Sperren des gemeinsam genutzten Objekts.
Ja, die Laufergebnisse sind in Ordnung.
Geben Sie über den synchronisierten Block den Erwerb der Objektsperre an, um den Zweck der Synchronisierung zu erreichen. Gibt es eine andere Methode, die durch die synchronisierte Methode erreicht werden kann?
Nach dem Synchronisationsprinzip: Wenn Sie eine gemeinsame Objektsperre oder Klassensperre erhalten können, kann eine Synchronisation erreicht werden. Können wir dies also erreichen, indem wir eine Klassensperre teilen?
Ja, wir können statische Synchronisationsmethoden verwenden, die nur vom Klassenobjekt selbst aufgerufen werden können und nicht durch Instanziieren eines Klassenobjekts. Wenn dann die Sperre dieser statischen Methode erhalten wird, wird diese Klassensperre erhalten, und diese Klassensperren sind alle TestThread-Klassensperren, und der Zweck des Erhaltens der gemeinsam genutzten Klassensperre wird erreicht.
Der Implementierungscode lautet wie folgt:
package thread_test; /** * 测试扩展Thread类实现的多线程程序 * * @author ciding * @createTime Dec 7, 2011 9:37:25 AM * */ public class TestThread extends Thread{ private int threadnum; public TestThread(int threadnum) { this.threadnum = threadnum; } public static synchronized void staticTest(int threadnum) { for(int i = 0;i<1000;i++){ System.out.println("NO." + threadnum + ":" + i ); } } public static void main(String[] args) throws Exception { for(int i=0; i<10; i++){ new TestThread(i).start(); Thread.sleep(1); } } @Override public void run(){ staticTest(threadnum); } }
Das laufende Ergebnis ist das gleiche wie im zweiten Beispiel.
Der obige Inhalt erklärt hauptsächlich zwei Probleme: Synchronisationsblock und Synchronisationsmethode.
1. Synchronisationsblock: Die erhaltene Objektsperre ist die Flag-Objektsperre in der Synchronisierung (Flag).
2. Synchrone Methode: Was erhalten wird, ist das Klassenobjekt, zu dem die Methode gehört, und die Klassenobjektsperre.
Statische Synchronisierungsmethode: Da mehrere Threads sie gemeinsam nutzen, wird sie definitiv synchronisiert.
Anstelle einer statischen Synchronisierungsmethode wird nur im Singleton-Modus synchronisiert.
Weitere Erklärungen zur grundlegenden Verwendung des synchronisierten Schlüsselworts in der Java-Multithread-Programmierung finden Sie auf der chinesischen PHP-Website!