Dieser Artikel beschreibt den Unterschied zwischen synchronisiertem (Objektschloss) und statischer synchronisierter (Klassenschloss) in Java. Teilen Sie es für Ihre Referenz wie folgt weiter:
Der Unterschied zwischen synchronisierter und statischer Synchronisierung
Durch die Analyse der Analyse dieser beiden Verwendungen können wir das Konzept der Sperrung in Java verstehen. Eines ist ein Instanzschloss (gesperrt auf einem Instanzobjekt. Wenn die Klasse ein Singleton ist, hat das Schloss auch das Konzept einer globalen Schloss) und das andere ein globales Schloss (das Schloss wird auf eine Klasse abzielt. Egal wie viele Objekte die Instanz ist, die Threads teilen die Sperre). Die Instanzschloss entspricht dem synchronisierten Schlüsselwort, während die Klassensperrung (Global Lock) dem statischen synchronisierten (oder in der Klasse- oder Klassenloader -Objekt der Klasse gesperrt) entspricht.
Der folgende Artikel enthält eine gute Zusammenfassung:
1. Der Unterschied zwischen synchronisierter und statischer Synchronisierung
Synchronisierte sperrt die aktuelle Instanz (aktuelles Objekt) der Klasse, um zu verhindern, dass andere Threads gleichzeitig auf alle synchronisierten Blöcke der Instanz der Klasse zugreifen. Beachten Sie, dass dies die "aktuelle Instanz der Klasse" ist. Es gibt keine solche Einschränkung in zwei verschiedenen Fällen der Klasse.
Anschließend kontrolliert statische Synchronisierung den gleichzeitigen Zugriff aller Instanzen der Klasse, und statische Synchronisierte schränkt alle Instanzen der Klasse in Multi-Threads ein, um auf den Codeblock zuzugreifen, der gleichzeitig der Klasse in JVM entspricht. Wenn in einer Methode oder einem Codeblock in einer Klasse synchronisiert ist, verfügt die Instanz auch über einen Überwachungsblock, um zu verhindern, dass Threads gleichzeitig auf den synchronisierten Schutzblock der Instanz zugreifen. Die statische Synchronisierung ist ein Überwachungsblock, der allen Fällen der Klasse gemeinsam ist. Dies ist der Unterschied zwischen den beiden. Mit anderen Worten, synchronisiert entspricht dies. (Später adressiert)
Ein japanischer Autor, Jie Chenghaos "Java Multithreaded Design Muster" hat eine solche Kolumne:
pulbic class there () {public synchronisierte void isynca () {} public synchronisierte void isyncb () {} public static synchronisierte void csynca () {} öffentliche statische synchronisierte void csyncb () {}}}}}}}}}}}}}}}}Wenn es also zwei Instanzen x und y von etwas Klasse gibt, auf welchen Fall ist es dann, wenn die folgende Gruppe von Methoden gleichzeitig von mehreren Threads zugegriffen wird?
Axissynca () und X.ISSyncb ()
bxissynca () und y.issynca ()
cxcsynca () und y.csyncb ()
dxissynca () und etwas.csynca ()
Hier ist klar, dass es beurteilt werden kann:
A, sind alle synchronisierte Domänenzugriffe auf dieselbe Instanz (x) und können daher nicht gleichzeitig zugegriffen werden. (Verschiedene synchronisierte Domänen, die in Multithreads zugreifen, können nicht gleichzeitig zugegriffen werden)
Wenn X.ISSynca () in mehreren Threads zugegriffen wird, da es immer noch dieselbe Instanz ist und auf derselben Methode gesperrt ist, kann es nicht gleichzeitig in mehreren Threads zugegriffen werden. (Auf die gleiche synchronisierte Domäne, auf die in Multithreads auf X zugegriffen wird, kann nicht gleichzeitig zugegriffen werden.)
B ist für verschiedene Instanzen, sodass gleichzeitig zugegriffen werden kann (Objektsperrungen haben keine Sperrbeschränkungen für verschiedene Objektinstanzen).
C, weil es statische synchronisierte, werden verschiedene Instanzen immer noch eingeschränkt, was etwas entspricht.
Was ist also mit D?, Auf die Antwort im Buch kann gleichzeitig zugegriffen werden. Der Grund für die Antwort ist, dass Synchronzied ist, dass sich die Instanzmethode und die Synchronzed -Klassenmethode von der Sperre unterscheiden.
Persönliche Analyse bedeutet, dass synchronisierte und statische Synchronisierung zwei Banden entspricht, von denen jede seine eigene Kontrolle hat, und es gibt keine Einschränkungen aufeinander und kann gleichzeitig zugegriffen werden.
Zum Beispiel:
public class testSynchronized {public synchronisierte void test1 () {int i = 5; while (i--> 0) {System.out.println (Thread.currentThread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException dh) {}}} public static synchronisierte void test2 () {int i = 5; while (i--> 0) {System.out.println (Thread.currentThread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException dh) {}}} public static void main (String [] args) {endgültig testSynchronisierte myt2 = new Testsynchronized (); Thread test1 = neuer Thread (neuer runnable () {public void run () {myt2.test1 ();}}, "test1"); Thread test2 = neuer Thread (new Runnable () {public void run () {Testsynchronized.test2 ();}}, "test2"); Test1.Start (); Test2.Start (); // testrunnable tr = new Testrunnable (); // Thread Test3 = neuer Thread (tr); // Test3.Start (); }}Test1: 4 Test2: 4 Test1: 3 Test2: 3 Test2: 2 Test1: 2 Test2: 1 Test1: 1 Test1: 0 Test2: 0
Das obige Codesynchronisierte modifiziert die statische Methode und die Instanzmethode gleichzeitig, aber die laufenden Ergebnisse werden abwechselnd durchgeführt, was beweist, dass Klassensperrungen und Objektschlösser zwei verschiedene Sperren sind, die verschiedene Regionen steuern, und sie nicht miteinander stören. In ähnlicher Weise können Threads Objektschlösser erhalten, sie können diese Art von Schloss auch erhalten, dh zwei gleichzeitig zwei Schlösser erhalten, was zulässig ist.
abschließend:
A: Synchronisiertes statisches ist der Umfang einer bestimmten Klasse. Synchronisiertes statisches CSYNC {} verhindert, dass mehrere Instanzen in mehreren Threads gleichzeitig auf die synchronisierte statische Methode in dieser Klasse zugreifen. Es funktioniert an allen Objektinstanzen einer Klasse.
B: Synchronisiert ist der Umfang einer Instanz. Synchronisierte issync () {} verhindert, dass diese Instanz gleichzeitig auf die synchronisierte Methode dieser Klasse zugreift.
Tatsächlich ist es sehr einfach zusammenzufassen.
2. Die Differenz zwischen synchronisierter Methode und synchronisiertem Code schnell
Es gibt keinen Unterschied zwischen synchronisierten Methoden () {} und synchronisierten (this) {}, aber synchronisierte Methoden () {} ist bequem für das Leseverständnis, während synchronisierte (dieses) {} Konflikte, die den Zugriffsbereiche genauer beschränken, genauer steuern und manchmal effizienter abschneiden können.
Vergleich der Effizienz zwischen zwei Methoden:
1. Synchronisieren Sie den Block, der Code ist wie folgt:
Import Java.util.Concurrent.Countdownlatch; import Java.util.concurrent.executorService; import Java.util.concurrent.executors; public class testSynchronized { / ** * @param args * / public static void main (String [] args) {ExecutorService Service = Executors.NewCachedThreadpool (); endgültiger Countdownlatch CDORDER = NEUER COUNDDOWNLATCH (1); endgültiger Countdownlatch CDanswer = new Countdownlatch (3); endgültige SynchnonizedClass SC = New SynchonizedClass (); für (int i = 0; i <3; i ++) {runnable runnable = new Runnable () {public void run () {try {cdorder.await (); sc.start (); CDanswer.countdown (); } catch (Ausnahme e) {e.printstacktrace (); }}}; service.execute (runnable); } try {thread.sleep ((lang) (math.random ()*10000)); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Ausführungsbefehl veröffentlichen"); cdorder.countdown (); langer BeginTime = System.currentTimemillis (); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Der Befehl wurde gesendet, das auf das Ergebnis wartet"); CDANSWER.AWAIT (); System.out.println ("Thread" + Thread.currentThread (). GetName ()) + "Alle Antwortergebnisse wurden empfangen, die Zeit ist:" + (System.currentTimemillis ()-Begintime)); } catch (Ausnahme e) {e.printstacktrace (); } service.shutdown (); }} Klasse SynchonizedClass {public void start () löst InterruptedException {thread.sleep (100); // Führen Sie eine andere Logik aus, um die zeitsynchronisierte (this) {System.out.Out.println zu konsumieren ("i rief es mit 10 ms"); }}} Die Betriebsergebnisse sind wie folgt:
Thread Main gibt den Befehl aus Ausführungsbefehl, der Thread Main hat den Befehl gesendet und auf das Ergebnis gewartet, das ich lief und 10 ms verwendet habe
Ich habe 10 ms mit 10 ms gelaufen
Ich habe 10 ms mit 10 ms gelaufen
Der Thread Main hat alle Antwortergebnisse erhalten, und die Zeit ist: 110
Die Synchronisationsmethode ist der Code wie folgt:
Import Java.util.Concurrent.Countdownlatch; import Java.util.concurrent.executorService; import Java.util.concurrent.executors; public class testSynchronized { / ** * @param args * / public static void main (String [] args) {ExecutorService Service = Executors.NewCachedThreadpool (); endgültiger Countdownlatch CDORDER = NEUER COUNDDOWNLATCH (1); endgültiger Countdownlatch CDanswer = new Countdownlatch (3); endgültige SynchnonizedClass SC = New SynchonizedClass (); für (int i = 0; i <3; i ++) {runnable runnable = new Runnable () {public void run () {try {cdorder.await (); sc.start (); CDanswer.countdown (); } catch (Ausnahme e) {e.printstacktrace (); }}}; service.execute (runnable); } try {thread.sleep ((lang) (math.random ()*10000)); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Ausführungsbefehl veröffentlichen"); cdorder.countdown (); langer BeginTime = System.currentTimemillis (); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Der Befehl wurde gesendet, das auf das Ergebnis wartet"); CDANSWER.AWAIT (); System.out.println ("Thread" + Thread.currentThread (). GetName ()) + "Alle Antwortergebnisse wurden empfangen, die Zeit ist:" + (System.currentTimemillis ()-Begintime)); } catch (Ausnahme e) {e.printstacktrace (); } service.shutdown (); }} class SynchonizedClass {public synchronisierte void start () löst unterbrochene Ausnahme {Thread.sleep (100); // andere logische Zeit aus. //}}}Die Betriebsergebnisse sind wie folgt:
Thread Main gibt den Befehl aus Ausführungsbefehl, der Thread Main hat den Befehl gesendet und auf das Ergebnis gewartet, das ich lief und 10 ms verwendet habe
Ich habe 10 ms mit 10 ms gelaufen
Ich habe 10 ms mit 10 ms gelaufen
Der Thread Main hat alle Antwortergebnisse erhalten, und die Zeit ist: 332
Der Unterschied zwischen den beiden ist: 222 ms.
Der Vergleich zeigt, dass Synchroncodeblöcke effizienter sind als Synchronisationsmethoden.
Ergänzungsgedächtnis:
1. Es gibt zwei Bereiche synchronisierter Schlüsselwörter:
1) Es befindet sich innerhalb einer Objektinstanz. Synchronisierte Amethod () {} kann verhindern, dass mehrere Threads gleichzeitig auf die synchronisierte Methode dieses Objekts zugreifen (wenn ein Objekt mehrere synchronisierte Methoden aufweist, sofern ein Thread gleichzeitig auf eine der synchronisierten Methoden zugreift, können andere Threads nicht auf synchronisierte Methoden zugreifen). Zu diesem Zeitpunkt ist die synchronisierte Methode verschiedener Objektinstanzen ununterbrochen. Das heißt, andere Threads können weiterhin auf die synchronisierte Methode in einer anderen Objektinstanz derselben Klasse zugreifen.
2) Es ist der Umfang einer bestimmten Klasse. Synchronisierte statische AstaticMethod {} verhindert, dass verschiedene Instanzobjekte (oder dasselbe Instanzobjekt) in mehreren Threads gleichzeitig auf die synchronisierte statische Methode in dieser Klasse zugreifen. Es funktioniert an allen Objektinstanzen einer Klasse.
2. Zusätzlich zur Verwendung des synchronisierten Schlüsselworts vor der Methode kann das synchronisierte Schlüsselwort auch in einem Block in der Methode verwendet werden, was darauf hinweist, dass nur ein gegenseitig ausschließender Zugriff auf den Ressourcen dieses Blocks durchgeführt wird. Die Verwendung ist: synchronisiert (this) {/*block*/} (oder synchronisiert (obj) {/*block*/}), und sein Umfang ist das aktuelle Objekt;
3. Das synchronisierte Schlüsselwort kann nicht vererbt werden. Das heißt, die Methode der Basisklasse synchronisierte f () {} wird in der ererbten Klasse nicht automatisch f () {} synchronisiert, sondern wird f () {}. In der Erbschaftsklasse müssen Sie ausdrücklich festlegen, dass eine ihrer Methoden synchronisiert ist.
Ein gewisses Verständnis von synchronisiertem (dies) (erklären Sie die Objektsperrung gut, achten Sie auf das darin enthaltene Schlüsselwort)
1. Wenn zwei gleichzeitige Threads auf diesen synchronisierten (this) synchronisierten Codeblock in demselben Objektobjekt zugreifen, kann nur ein Thread innerhalb eines Zeitpunkts ausgeführt werden. Ein weiterer Thread muss warten, bis der aktuelle Thread diesen Codeblock ausführt, bevor er den Codeblock ausführen kann.
2. Wenn jedoch ein Thread auf einen synchronisierten (this) -Synchronisationscode-Codeblock eines Objekts zugreift, kann ein anderer Thread weiterhin auf den nicht synchronisierten (this) Synchronisationscodeblock in diesem Objekt zugreifen.
3.. Es ist besonders wichtig, dass bei einem Thread auf einen synchronisierten (this) -Synchronisationscode -Block eines Objekts zugreift, andere Threads den Zugriff auf alle anderen synchronisierten (this) -Synchronisationscodeblöcke im Objekt im Objekt blockieren.
4. Das dritte Beispiel gilt auch für andere Synchroncodeblöcke. Das heißt, wenn ein Thread auf einen synchronisierten (this) -Synchronisationscode -Codeblock eines Objekts zugreift, wird die Objektsperrung dieses Objekts erhalten. Infolgedessen werden andere Threads auf alle synchronen Code -Teile des Objektobjekts zugreifen.
5. Die oben genannten Regeln gelten auch für andere Objektschlösser.
Fügen Sie einen Code hinzu, um das Testen synchronisierter Schlüsselwörter zu erleichtern (einfache Modifikation)
public class testSynchronized {public void test1 () {synchronisiert (this) {int i = 5; while (i--> 0) {System.out.println (Thread.currentThread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}} public synchronisierte void test2 () {int i = 5; while (i--> 0) {System.out.println (Thread.currentThread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}} public synchronisierte void test3 () {int i = 5; while (i--> 0) {System.out.println (Thread.currentThread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException dh) {}}} public static void main (String [] args) {endgültig testSynchronisierte myt2 = new Testsynchronized (); endgültig testSynchronized myt3 = neuer Testsynchronized (); Thread test1 = neuer Thread (new Runnable () {public void run () {myt2.test2 ();}}, "test1"); Thread test2 = neuer Thread (new Runnable () {public void run () {myt2.test3 ();}}, "test3"); Test1.Start () ;; Test2.Start (); }} Auslaufergebnisse:
Test1: 4Test1: 3Test1: 2Test1: 1Test1: 0Test3: 4Test3: 3Test3: 2Test3: 1Test3: 0
Im Folgenden konzentrieren wir uns auf die Verwendung von sychronisierten in Java, was speziell: die Synchronisationsmethode und das synchronisierte blocksynchronisierte Schlüsselwort, das zwei Verwendungen enthält: die synchronisierte Methode und den synchronisierten Block enthält.
1. Synchronisierte Methode: Deklarieren Sie die synchronisierte Methode durch Hinzufügen des synchronisierten Schlüsselworts zur Methodenerklärung. wie:
öffentliches synchronisiertes void accessval (int newval);
Die synchronisierte Methode steuert den Zugriff auf Klassenelementvariablen: Jede Klasseninstanz entspricht einer Sperre, und jede synchronisierte Methode muss die Sperre der Klasseninstanz erhalten, die die Methode aufruft, bevor sie ausgeführt werden kann. Ansonsten ist der Faden, zu dem er gehört, blockiert. Sobald die Methode ausgeführt wurde, wird sie ausschließlich das Schloss besetzen. Das Schloss wird erst freigegeben, wenn es aus der Methode zurückkehrt. Der blockierte Thread kann das Schloss erhalten und in den ausführbaren Status eintreten. Dieser Mechanismus stellt sicher, dass gleichzeitig für jede Klasseninstanz höchstens eine der synchronisierten Mitgliedsfunktionen in einem ausführbaren Zustand (da höchstens man die Sperre erhalten kann, die der Klasseninstanz entspricht), wodurch die Zugriffskonflikte der Klassenmitgliedsvariablen effektiv vermieden werden (so lange wie alle möglichen Methoden, um Klassenmitgliedern zuzugreifen, die synchronisiert wurden).
In Java, nicht nur Klasseninstanzen, entspricht jede Klasse auch einer Schloss, sodass wir die statische Mitgliedsfunktion der Klasse als statisches Synchron angeben können, um den Zugriff auf die statischen Mitgliedsvariablen der Klasse zu steuern.
Der Nachteil der synchronisierten Methode: Ein großes Verfahren als synchronisierte Methode wirkt sich stark auf die Effizienz aus. Wenn die Methode der Thread -Klasse run () als synchronisiert erklärt wird, wird es in einer synchronisierten Methode dieser Klasse niemals erfolgreich sein, da sie während des gesamten Lebens des Threads gelaufen ist. Natürlich können wir dieses Problem lösen, indem wir den Code, der auf die Klassenmitglied -Variablen zugreift, in eine spezielle Methode aufgenommen, ihn als synchronisiert erklärt und in der Hauptmethode aufgerufen wird. Java bietet uns jedoch eine bessere Lösung, dh den synchronisierten Block.
2. Synchronisierter Block: Deklarieren Sie den synchronisierten Block durch das synchronisierte Schlüsselwort. Die Syntax ist wie folgt:
Synchronized (SyncObject) {// Code, der Zugriffskontrolle} ermöglicht} Der synchronisierte Block ist ein Codeblock, in dem der Code eine Sperre des Objektsynkobjekts erhalten muss (wie bereits erwähnt, kann er eine Klasseninstanz oder Klasse sein), bevor er ausgeführt werden kann. Der spezifische Mechanismus ist derselbe wie oben beschrieben. Da es auf jeden Codeblock abzielen und gesperrte Objekte jederzeit angegeben werden können, ist es flexibler.
Beachten:
Wenn Sie synchronisierte Schlüsselwörter verwenden, sollten Sie vermeiden, dass Sie Schlaf- oder Ertragsmethoden in synchronisierten Methoden oder synchronisierten Blöcken so weit wie möglich verwenden, da synchronisierte Programmblöcke Objektschlösser belegen. Wenn Sie sich also ausruhen, können andere Threads nur darauf ausgeführt werden, dass Sie darauf warten, dass Sie aufwachen und die Ausführung abschließen. Es beeinflusst nicht nur die Effizienz ernsthaft, sondern auch nicht logisch.
In ähnlicher Weise ist es nicht sinnvoll, die YEILD -Methode im synchronen Programmblock aufzurufen, um die CPU -Ressource aufzugeben, da Sie die Sperre besetzen und andere Mutex -Threads immer noch nicht auf den synchronen Programmblock zugreifen können. Natürlich können Threads, die nicht mit synchronen Programmblöcken zusammenhängen, mehr Ausführungszeit erhalten.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.