In diesem Kapitel werden wir synchronisierte Schlüsselwörter einführen. Der betreffende Inhalt umfasst:
1. Synchronisierter Prinzip
2. Synchronisierte Grundregeln
3. Synchronisierte Methode und synchronisierter Codeblock
4. Instanzschloss und Global Lock
1. Synchronisierter Prinzip
In Java hat jedes Objekt eine Synchronisationsschloss. Dies bedeutet auch, dass das Synchronisationsschloss auf dem Objekt vorhanden ist.
Wenn wir die synchronisierte Methode eines Objekts nennen, erwerben wir die Synchronisationsschloss des Objekts. Beispielsweise erfasst synchronisierte (OBJ) die Synchronisationsschloss des "OBJ -Objekts".
Der Zugriff auf Synchronisationsperren durch verschiedene Threads schließt sich gegenseitig aus. Mit anderen Worten, zu einem bestimmten Zeitpunkt kann die Synchronisationsschloss des Objekts nur durch einen Thread erhalten werden! Durch Synchronisationssperrs können wir in mehreren Threads einen sich gegenseitig ausschließenden Zugriff auf "Objekte/Methoden" erreichen. Zum Beispiel gibt es jetzt zwei Threads A und Thread B, die beide auf das "Synchronen Lock of Object OBJ" zugreifen. Nehmen wir an, dass die Synchronisationsschlosse "Obj's Synchronisation" ein paar Operationen erwerbt. B kann nur das "Synchronisationsschloss der OBJ" erhalten, bis ein Gewinde A "Synchrones Lock dieses Objekts" veröffentlicht und nur ausgeführt werden kann.
2. Synchronisierte Grundregeln
Wir fassen die grundlegenden Regeln von Synchron in die folgenden 3 zusammen und veranschaulichen sie anhand von Beispielen.
Artikel 1: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, werden andere Threads vom Zugriff auf die "synchronisierte Methode" oder "Synchronisierter Codeblock" des "Objekts" blockiert.
Artikel 2: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, können andere Threads weiterhin auf den asynchronisierten Codeblock von "dieses Objekt" zugreifen.
Artikel 3: Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierte Codeblock" von "einem bestimmten Objekt" zugreift, werden andere Threads aus dem Zugriff auf andere "synchronisierte Methoden" oder "synchronisierter Codeblock" von "The Object" blockiert.
Artikel 1
Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierte Codeblock" von "einem bestimmten Objekt" zugreift, werden andere Threads vom Zugriff auf die "synchronisierte Methode" oder "synchronisierter Codeblock" des "Objekts" blockiert.
Nachfolgend finden Sie das Demonstrationsprogramm, das "Synchronisierter Codeblock" entspricht.
Die Codekopie lautet wie folgt:
Klassenmyrelable implementiert runnable {
@Override
public void run () {
synchronisiert (this) {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
}
öffentliche Klasse Demo1_1 {
public static void main (String [] args) {
Runnable Demo = new Myrunable ();
Thread T1 = neuer Thread (Demo, "T1");
Thread T2 = neuer Thread (Demo, "T2");
t1.start ();
t2.Start ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T1 Loop 0
T1 Loop 1
T1 -Schleife 2
T1 Loop 3
T1 Loop 4
T2 Loop 0
T2 Loop 1
T2 Loop 2
T2 Loop 3
T2 Loop 4
Ergebnisse Beschreibung:
In der Run () -Methode gibt es einen "synchronisierten (diesen) Codeblock", und T1 und T2 sind Threads, die basierend auf dem Runnable -Objekt "Demo" erstellt wurden. Dies bedeutet, dass wir dies als "Demo -Runnable -Objekt" betrachten können. Wenn ein Thread ausgeführt wird, muss ein anderer Thread warten, bis der "Auslauf -Thread" die "Demo -Synchronisationssperrung" freigibt, bevor er ausgeführt werden kann.
Wenn Sie bestätigen, haben Sie dieses Problem herausgefunden. Dann ändern wir den obigen Code und führen ihn dann aus, um zu sehen, wie das Ergebnis ist, und feststellen, ob Sie verwirrt sind. Der geänderte Quellcode lautet wie folgt:
Die Codekopie lautet wie folgt:
Klasse MyThread erweitert Thread {
public myThread (String name) {
Super (Name);
}
@Override
public void run () {
synchronisiert (this) {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
}
öffentliche Klasse Demo1_2 {
public static void main (String [] args) {
Thread T1 = neuer MyThread ("T1");
Thread T2 = neuer MyThread ("T2");
t1.start ();
t2.Start ();
}
}
Code Beschreibung:
Wenn wir Demo1_2 und Demo1_1 vergleichen, stellten wir fest, dass die MyThread -Klasse in Demo1_2 direkt aus Thread geerbt wird und T1 und T2 beide MyThread Child Threads sind.
Glücklicherweise wird die "run () -Methode von Demo1_2" auch als synchronisiert (this) genannt, ebenso wie die "Run () -Methode von Demo1_1" auch als synchronisiert (this) genannt!
Ist also der Ausführungsprozess von Demo1_2 wie demo1_1?
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T1 Loop 0
T2 Loop 0
T1 Loop 1
T2 Loop 1
T1 -Schleife 2
T2 Loop 2
T1 Loop 3
T2 Loop 3
T1 Loop 4
T2 Loop 4
Ergebnisse Beschreibung:
Wenn dieses Ergebnis Sie überhaupt nicht überrascht, dann glaube ich, dass Sie ein tieferes Verständnis der synchronisierten und dies haben. Andernfalls lesen Sie die Analyse hier weiter.
Dies in synchronisiertem (dies) bezieht sich auf das "aktuelle Klassenobjekt", dh das aktuelle Objekt, das der Klasse entspricht, in der sich synchronisiert (dieses) befindet. Sein Zweck ist es, die "synchrone Schloss des aktuellen Objekts" zu erhalten.
Für Demo1_2 repräsentiert dies in synchronisiertem (dies) das MyThread -Objekt, während T1 und T2 zwei verschiedene MyThread -Objekte sind. Für das Demo1_1 -Paar repräsentiert dies in synchronisiertem (dies) das myRunable -Objekt.
Artikel 2
Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierte Codeblock" von "einem bestimmten Objekt" zugreift, können andere Threads weiterhin auf den asynchronisierten Codeblock von "dieses Objekt" zugreifen.
Nachfolgend finden Sie das Demonstrationsprogramm, das "Synchronisierter Codeblock" entspricht.
Die Codekopie lautet wie folgt:
Klassenanzahl {
// Methode mit synchronisiertem Synchronisationsblock enthält
public void synmethod () {
synchronisiert (this) {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Synmethode Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
// Asynchrone Methode
public void nonsynmethod () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "NonSynMethod Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
öffentliche Klasse Demo2 {
public static void main (String [] args) {
endgültige Count Count = New Count ();
// Erstellen Sie einen neuen T1, T1 nennt die Synmethode () -Methode des "Count -Objekts"
Thread T1 = neuer Thread (
New Runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "t1");
// Erstellen Sie einen neuen T2, T2 ruft die nichtsynMethod () -Methode des "Count -Objekts" auf
Thread T2 = neuer Thread (
New Runnable () {
@Override
public void run () {
count.nonsynmethod ();
}
}, "t2");
t1.start ();
t2.Start ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T1 Synmethod Loop 0
T2 Nonsynmethod Loop 0
T1 Synmethod Loop 1
T2 Nonsynmethod Loop 1
T1 Synmethod Loop 2
T2 Nonsynmethod Loop 2
T1 Synmethod Loop 3
T2 Nonsynmethod Loop 3
T1 Synmethod Loop 4
T2 Nonsynmethod Loop 4
Ergebnisse Beschreibung:
Zwei neue Kinderfäden T1 und T2 werden im Hauptfaden erstellt. T1 ruft die Synmethode () -Methode des Zählobjekts auf, das Synchronisationsblöcke enthält. Wenn T1 ausgeführt wird, ist synchronisiert (dies), um das "Zählsynchronisationsschloss" zu erhalten.
Artikel 3
Wenn ein Thread auf die "synchronisierte Methode" oder "synchronisierten Codeblock" von "einem bestimmten Objekt" zugreift, zugänglich wird auf andere "synchronisierte Methoden" oder "synchronisierter Codeblock" des "Objekts" zugegriffen.
Wir werden auch den nichtsynmeThod () -Methodenkörper im obigen Beispiel mit synchronisiertem (this) ändern. Der geänderte Quellcode lautet wie folgt:
Die Codekopie lautet wie folgt:
Klassenanzahl {
// Methode mit synchronisiertem Synchronisationsblock enthält
public void synmethod () {
synchronisiert (this) {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "Synmethode Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
// enthält auch die synchronisierte Synchronisationsblockmethode
public void nonsynmethod () {
synchronisiert (this) {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName () + "NonSynMethod Loop" + i);
}
} catch (InterruptedException dh) {
}
}
}
}
öffentliche Klasse Demo3 {
public static void main (String [] args) {
endgültige Count Count = New Count ();
// Erstellen Sie einen neuen T1, T1 nennt die Synmethode () -Methode des "Count -Objekts"
Thread T1 = neuer Thread (
New Runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "t1");
// Erstellen Sie einen neuen T2, T2 ruft die nichtsynMethod () -Methode des "Count -Objekts" auf
Thread T2 = neuer Thread (
New Runnable () {
@Override
public void run () {
count.nonsynmethod ();
}
}, "t2");
t1.start ();
t2.Start ();
}
}
(Einmal) Ausführungsergebnis:
Die Codekopie lautet wie folgt:
Synmethod (): 11
synblock (): 3
4. Instanzschloss und Global Lock
Instanzschloss-auf einem Instanzobjekt gesperrt. Wenn die Klasse ein Singleton ist, hat das Schloss auch das Konzept eines globalen Schlosses.
Das synchronisierte Schlüsselwort entspricht der Instanzschloss.
Global Lock- Dieses Schloss richtet sich an eine Klasse.
Das globale Schloss entspricht statischer synchronisiertem (oder auf dem Objekt der Klasse oder des Klassenloaders dieser Klasse).
Es gibt ein sehr lebendiges Beispiel für "Instanzschloss" und "Global Lock":
Die Codekopie lautet wie folgt:
pulbische Klasse etwas {
public synchronisierte void isynca () {}
public synchronisierte void isyncb () {}
public statische synchronisierte void CSynca () {}
public statische synchronisierte void CSyncb () {}
}
Angenommen, etwas hat zwei Fälle x und y. Analysieren Sie die von den folgenden vier Ausdruckssätzen erworbenen Schlösser.
(01) X.ISSYNCA () und X.ISSYNCB ()
(02) X.ISSYNCA () und Y.ISSYNCA ()
(03) x.csynca () und y.csyncb ()
(04) X.ISSynca () und etwas.csynca ()
(01) kann nicht gleichzeitig zugegriffen werden. Weil Issynca () und isSyncb () beide Synchronisationssperrungen sind, die auf dasselbe Objekt zugreifen (Objekt X)!
Die Codekopie lautet wie folgt:
// Locktest2.java Quellcode
Klasse etwas {
public synchronisierte void isynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issynca");
}
} catch (InterruptedException dh) {
}
}
public synchronisierte void isyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issyncb");
}
} catch (InterruptedException dh) {
}
}
public statische synchronisierte void CSynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (InterruptedException dh) {
}
}
public static synchronisierte void csyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csyncb");
}
} catch (InterruptedException dh) {
}
}
}
public class lockest2 {
Etwas x = neu etwas ();
Etwas y = neu etwas ();
// vergleiche (02) X.ISSynca () mit Y.ISSynca ()
private void test2 () {
// Erstellen Sie einen neuen T21, und T21 ruft X.ISSynca () auf
Thread T21 = neuer Thread (
New Runnable () {
@Override
public void run () {
X.ISSynca ();
}
}, "t21");
// Erstellen Sie einen neuen T22, und T22 ruft X.ISSYNCB () auf
Thread T22 = neuer Thread (
New Runnable () {
@Override
public void run () {
y.issynca ();
}
}, "t22");
t21.start ();
T22.Start ();
}
public static void main (String [] args) {
LockTest2 Demo = new LockTest2 ();
Demo.Test2 ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T11: Issynca
T12: issyncb
T12: issyncb
T12: issyncb
T12: issyncb
T12: issyncb
(02) kann gleichzeitig zugegriffen werden. Da es nicht auf die Synchronisationsschloss desselben Objekts zugreift, greift X.ISSynca () auf die Synchronisationsschloss von X zu, während y.issynca () auf die Synchronisationsschloss von Y zugreift.
Die Codekopie lautet wie folgt:
// Locktest2.java Quellcode
Klasse etwas {
public synchronisierte void isynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issynca");
}
} catch (InterruptedException dh) {
}
}
public synchronisierte void isyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issyncb");
}
} catch (InterruptedException dh) {
}
}
public statische synchronisierte void CSynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (InterruptedException dh) {
}
}
public static synchronisierte void csyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csyncb");
}
} catch (InterruptedException dh) {
}
}
}
public class lockest2 {
Etwas x = neu etwas ();
Etwas y = neu etwas ();
// vergleiche (02) X.ISSynca () mit Y.ISSynca ()
private void test2 () {
// Erstellen Sie einen neuen T21, und T21 ruft X.ISSynca () auf
Thread T21 = neuer Thread (
New Runnable () {
@Override
public void run () {
X.ISSynca ();
}
}, "t21");
// Erstellen Sie einen neuen T22, und T22 ruft X.ISSYNCB () auf
Thread T22 = neuer Thread (
New Runnable () {
@Override
public void run () {
y.issynca ();
}
}, "t22");
t21.start ();
T22.Start ();
}
public static void main (String [] args) {
LockTest2 Demo = new LockTest2 ();
Demo.Test2 ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
T21: Issynca
T22: Issynca
(03) kann nicht gleichzeitig zugegriffen werden. Weil CSYNCA () und CSYNCB () beide statische Typen sind, ist X.csynca () etwas entspricht. ISSynca () und Y.Csyncb () entspricht etwas. ISSyncb (), sodass sie eine Synchronisationsschloss teilen und nicht gleichzeitig gefragt werden.
Die Codekopie lautet wie folgt:
// LockTest3.java Quellcode
Klasse etwas {
public synchronisierte void isynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issynca");
}
} catch (InterruptedException dh) {
}
}
public synchronisierte void isyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issyncb");
}
} catch (InterruptedException dh) {
}
}
public statische synchronisierte void CSynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (InterruptedException dh) {
}
}
public static synchronisierte void csyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csyncb");
}
} catch (InterruptedException dh) {
}
}
}
öffentliche Klasse locktest3 {
Etwas x = neu etwas ();
Etwas y = neu etwas ();
// vergleiche (03) x.csynca () mit y.csyncb ()
private void test3 () {
// Erstellen Sie einen neuen T31, und T31 ruft X.ISSynca () auf
Thread T31 = neuer Thread (
New Runnable () {
@Override
public void run () {
X.Csynca ();
}
}, "t31");
// Erstellen Sie einen neuen T32, und T32 ruft X.ISSyncb () auf
Thread T32 = neuer Thread (
New Runnable () {
@Override
public void run () {
y.csyncb ();
}
}, "t32");
t31.start ();
t32.Start ();
}
public static void main (String [] args) {
LockTest3 Demo = new LockTest3 ();
Demo.Test3 ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T31: CSynca
T31: CSynca
T31: CSynca
T31: CSynca
T31: CSynca
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
T32: CSYNCB
(04) kann gleichzeitig zugegriffen werden. Da isSynca () eine Instanzmethode ist, verwendet X.ISSynca () die Sperre von Objekt X; Daher können sie gleichzeitig zugegriffen werden.
Die Codekopie lautet wie folgt:
// Locktest4.java Quellcode
Klasse etwas {
public synchronisierte void isynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issynca");
}
} catch (InterruptedException dh) {
}
}
public synchronisierte void isyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": issyncb");
}
} catch (InterruptedException dh) {
}
}
public statische synchronisierte void CSynca () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csynca");
}
} catch (InterruptedException dh) {
}
}
public static synchronisierte void csyncb () {
versuchen {
für (int i = 0; i <5; i ++) {
Thread.Sleep (100);
System.out.println (Thread.currentThread (). GetName ()+": csyncb");
}
} catch (InterruptedException dh) {
}
}
}
öffentliche Klasse locktest4 {
Etwas x = neu etwas ();
Etwas y = neu etwas ();
// vergleiche (04) X.ISSynca () mit etwas.csynca ()
private void test4 () {
// Erstellen Sie einen neuen T41, und T41 ruft X.ISSynca () auf
Thread T41 = neuer Thread (
New Runnable () {
@Override
public void run () {
X.ISSynca ();
}
}, "t41");
// Erstellen Sie einen neuen T42, und T42 ruft X.ISSyncb () auf
Thread T42 = neuer Thread (
New Runnable () {
@Override
public void run () {
Etwas.csynca ();
}
}, "t42");
T41.Start ();
T42.Start ();
}
public static void main (String [] args) {
LockTest4 Demo = new LockTest4 ();
Demo.Test4 ();
}
}
Auslaufergebnisse:
Die Codekopie lautet wie folgt:
T41: Issynca
T42: CSynca
T41: Issynca
T42: CSynca
T41: Issynca
T42: CSynca
T41: Issynca
T42: CSynca
T41: Issynca
T42: CSynca