Multithread-Parallelität kann in JAVA durch die synchronisierte Anweisung erreicht werden. Mithilfe synchronisierter Codeblöcke stellt die JVM sicher, dass jeweils nur ein Thread die Sperre für ein bestimmtes Objekt halten kann. Der Sperrmechanismus ermöglicht mehreren Threads den sicheren Zugriff auf kritische Ressourcen.
Der Synchronisationscode ist wie folgt geschrieben:
Code 1:
Object obj = new Object(); ... synchronisiert(obj) { //TODO: Auf kritische Ressourcen zugreifen} Das Multithreading von JAVA ist immer voller Fallen. Wenn wir Boolean als synchronisiertes Objekt verwenden, können die folgenden zwei Situationen auftreten:
1. Es wird angenommen, dass ein Objekt gesperrt ist, tatsächlich werden jedoch verschiedene Objekte synchronisiert.
Code 2:
private volatile Boolean isTrue = false; publich void aMethod() { ... synchronisiert(isTrue) { isTrue = !isTrue; //TODO: Zugriff auf kritische Ressourcen isTrue = !isTrue; Auf den ersten Blick ist an dem obigen Code nichts auszusetzen, da synchronisiert (isTrue) nur ein Thread gleichzeitig auf kritische Ressourcen zugreifen kann. Dies ist jedoch nicht der Fall. Denn die beiden Konstanten false und true entsprechen zwei unterschiedlichen Objekten. Wenn sich isTrue ändert, ist es wahrscheinlich, dass verschiedene Threads unterschiedliche Objekte synchronisieren. Das automatische Boxen von JAVA ändert „false“ in „Boolean.FALSE“ und „true“ in „Boolean.TRUE“ (dies zeigt auch, dass das Ergebnis dasselbe ist, wenn „false“ in „Boolean.FALSE“ geändert wird). Schreiben Sie den Testcode für eine der oben genannten Situationen wie folgt:
Code 3:
public class BooleanTest { private volatile Boolean isTrue = Boolean.FALSE; //Es ist das Gleiche, wenn Sie hier false verwenden public void aMethod() { for(int i=0;i<10;i++) { Thread t = new Thread() { public void run() { synchronisiert(isTrue) { isTrue = !isTrue; System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue); try{ Double ran = 1000 * Math.random(); Thread.sleep(ran.intValue()); }catch(InterruptedException e) {} if(!isTrue) System.out.println( Thread.currentThread().getName() + " - Oh, Nein!"); isTrue = !isTrue; t.start(); } } public static void main(String... args) { BooleanTest bt = new BooleanTest(} } Wenn Sie den obigen Code ausführen, wird von Zeit zu Zeit „-Oh, Nein!“ angezeigt, was darauf hinweist, dass verschiedene Threads gleichzeitig in den synchronisierten Codeblock eintreten.
2. Es wird angenommen, dass verschiedene Objekte synchronisiert werden, aber es handelt sich tatsächlich um ein Objekt.
Manchmal möchten wir möglicherweise mehrere Objekte synchronisieren. Wenn Boolean als synchronisiertes Objekt verwendet wird, ist es wahrscheinlich, dass zwei Synchronisierungsblöcke, die keine Beziehung haben sollten, dieselbe Objektsperre verwenden. Beispiele sind wie folgt:
Code 4:
private volatile Boolean aBoolean = Boolean.FALSE; private volatile Boolean anotherBoolean = false; public void aMethod() { ... synchronisiert(aBoolean) { //TODO: Zugriff auf kritische Ressource 1 } ... } public void anotherMethod() { . .. synchronisiert(anotherBoolean) { //TODO: Auf kritische Ressource 2 zugreifen } ... } Nehmen Sie an, dass aMethod und anotherMethod ursprünglich von zwei Sätzen unabhängiger Threads aufgerufen werden. Da Boolean.FALSE und false jedoch auf dasselbe Objekt verweisen, kann der Zugriff auf kritische Ressource 2 durch kritische Ressource 1 blockiert werden (und umgekehrt).
Die beiden oben genannten Situationen weisen darauf hin, dass bei der Verwendung synchronisierter Blöcke versucht werden sollte, boolesche Objekte nicht als synchronisierte Objekte zu verwenden, da sonst unerwartete Probleme auftreten oder bei zukünftigen Codeänderungen Traps auftreten können.
Daraus lässt sich auch erkennen, dass jede Synchronisation von Konstanten riskant ist. Wenn Sie boolesche Werte synchronisieren müssen, müssen Sie den neuen Operator verwenden, um ein boolesches Objekt zu erstellen.