Der folgende Code zeigt, wie bestimmte Klassenmethoden synchronisiert werden:
Kopieren Sie den Codecode wie folgt:
Paket mythread;
Die öffentliche Klasse SyncThread erweitert Thread
{
private static String sync = "";
private String methodType = "";
private statische Void-Methode (String s)
{
synchronisiert (sync)
{
sync = s;
System.out.println(s);
while (wahr);
}
}
public void method1()
{
Methode("Methode1");
}
public static void staticMethod1()
{
method("staticMethod1");
}
public void run()
{
if (methodType.equals("static"))
staticMethod1();
else if (methodType.equals("nonstatic"))
method1();
}
public SyncThread(String methodType)
{
this.methodType = methodType;
}
public static void main(String[] args) löst eine Ausnahme aus
{
SyncThread sample1 = new SyncThread("nonstatic");
SyncThread sample2 = new SyncThread("static");
probe1.start();
sample2.start();
}
}
Die Laufergebnisse sind wie folgt:
Kopieren Sie den Codecode wie folgt:
Methode1
staticMethod1
Viele Leser werden vielleicht überrascht sein, die oben genannten Laufergebnisse zu sehen. Im obigen Code verwenden die Methoden method1 und staticMethod1 die statische Zeichenfolgenvariable sync für die Synchronisierung. Nur eine dieser beiden Methoden kann gleichzeitig ausgeführt werden, und beide Methoden führen die Endlosschleifenanweisung in Zeile 014 aus. Daher kann das Ausgabeergebnis nur eines von method1 und staticMethod1 sein. Dieses Programm gibt jedoch beide Zeichenfolgen aus.
Der Grund für dieses Ergebnis ist sehr einfach, wir werden es erkennen, wenn wir uns Zeile 012 ansehen. Es stellt sich heraus, dass der Wert von sync in dieser Zeile geändert wird. Hier möchte ich über den String-Typ in Java sprechen. Der String-Typ unterscheidet sich von anderen komplexen Typen in Java. Wenn Sie eine Variable vom Typ String verwenden, erstellt Java eine neue Instanz des Typs String, solange Sie der Variablen einmal einen Wert zuweisen. Wie im folgenden Code gezeigt:
Kopieren Sie den Codecode wie folgt:
String s = "Hallo";
System.out.println(s.hashCode());
s = „Welt“;
System.out.println(s.hashCode());
im Code oben. Die HashCode-Werte der ersten s und der neu zugewiesenen s sind unterschiedlich. Da zum Erstellen einer Instanz der String-Klasse nicht die Verwendung von new erforderlich ist, achten Sie beim Synchronisieren einer Variablen vom Typ String darauf, dieser Variablen keinen Wert zuzuweisen, da die Variable sonst nicht synchronisiert wird.
Da in Zeile 012 eine neue Instanz für die Synchronisierung erstellt wurde und Methode1 zuerst ausgeführt wird, ist der Wert von Sync nicht mehr der ursprüngliche Wert, und Methode1 sperrt weiterhin die Synchronisierungsvariable Der Anfangswert . Zu diesem Zeitpunkt wird staticMethod1 zufällig mit synchronisiert(sync) ausgeführt. Die Synchronisierung, die in der Methode staticMethod1 gesperrt werden soll, ist nicht mehr dieselbe. Daher wurde die Synchronisierung der beiden Methoden zerstört.
Die Lösung des oben genannten Problems besteht natürlich darin, Zeile 012 zu entfernen. Diese Zeile wird diesem Beispiel nur hinzugefügt, um zu veranschaulichen, dass bei der Verwendung von Klassenvariablen zum Synchronisieren von Methoden die Synchronisation zwischen Methoden zerstört wird, wenn der Wert der Synchronisationsvariablen im synchronisierten Block geändert wird. Um diese Situation vollständig zu vermeiden, können Sie beim Definieren von Synchronisationsvariablen das Schlüsselwort final verwenden. Beispielsweise kann Zeile 005 im obigen Programm in die folgende Form geändert werden:
Kopieren Sie den Codecode wie folgt:
private final static String sync = "";
Nach Verwendung des Schlüsselworts final kann sync ihm nur dann einen Wert zuweisen, wenn es definiert ist, und es kann später nicht mehr geändert werden. Wenn sync an anderer Stelle im Programm ein Wert zugewiesen wird, wird das Programm nicht kompiliert. In Entwicklungstools wie Eclipse werden Eingabeaufforderungen direkt an der falschen Stelle angezeigt.
Wir können synchronisierte Blöcke aus zwei Perspektiven verstehen. Wenn man es aus der Perspektive von Klassenmethoden versteht, können die entsprechenden Methoden über Klassenvariablen synchronisiert werden. Wenn Sie es aus der Perspektive von Klassenvariablen verstehen, können Sie mithilfe synchronisierter Blöcke sicherstellen, dass nur eine Methode gleichzeitig auf eine Klassenvariable zugreifen kann. Unabhängig davon, aus welchem Blickwinkel Sie es verstehen, ist ihr Wesen dasselbe: Sie verwenden Klassenvariablen, um Synchronisationssperren zu erhalten, und erreichen die Synchronisation durch den gegenseitigen Ausschluss von Synchronisationssperren.
Hinweis: Wenn Sie synchronisierte Blöcke verwenden, sollten Sie sich darüber im Klaren sein, dass synchronisierte Blöcke nur Objekte als Parameter verwenden können. Wenn es sich um einen einfachen Variablentyp handelt (z. B. int, char, boolean usw.), kann synchronisiert nicht für die Synchronisierung verwendet werden.