0. Leitfragecode
Der folgende Code zeigt einen Zähler und zwei Threads führen gleichzeitig eine Akkumulationsoperation für i aus, wobei jeder davon 1.000.000 Mal ausgeführt wird. Das Ergebnis, das wir erwarten, ist definitiv i=2000000. Aber nachdem wir es mehrmals ausgeführt haben, werden wir feststellen, dass der Wert von i immer kleiner als 2000000 ist. Dies liegt daran, dass das Ergebnis eines Threads das andere überschreibt, wenn zwei Threads gleichzeitig in i schreiben 🎜>
public class AccountingSync implements Runnable { static int i = 0; public void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { AccountingSync accountingSync = new AccountingSync(); Thread t1 = new Thread(accountingSync); Thread t2 = new Thread(accountingSync); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
Um dieses Problem grundsätzlich zu lösen, müssen wir sicherstellen, dass mehrere Threads vollständig synchronisiert sind, wenn sie auf i ausgeführt werden. Mit anderen Worten, Thread A schreibt bei der Synchronisierung Die Aufgabe besteht darin, den synchronisierten Code zu sperren, sodass jeweils nur ein Thread den Synchronisationsblock betreten kann, wodurch die Sicherheit zwischen Threads gewährleistet wird. Genau wie im obigen Code kann die i++-Operation nur gleichzeitig ausgeführt werden Ein Thread wird ausgeführt.
2. Verwendung des synchronisierten Schlüsselworts
Objektsperre angeben: Sperren Sie das angegebene Objekt und geben Sie den synchronisierten Codeblock ein, um das angegebene Objekt zu erhalten. Die Sperre
wirkt direkt darauf Die Instanzmethode: Sie entspricht dem Sperren der aktuellen Instanz. Das Eingeben des Synchronisierungscodeblocks erfordert das Erhalten der Sperre der aktuellen Instanz (dies erfordert, dass beim Erstellen des Threads dieselbe ausführbare Instanz verwendet werden muss).
Es gilt der folgende Code Hier ist zu beachten, dass das angegebene Objekt statisch sein muss. Andernfalls wird das Objekt nicht jedes Mal miteinander geteilt, und die Bedeutung des Sperrens ist unterschiedlich wird nicht mehr existieren.
public class AccountingSync implements Runnable { final static Object OBJECT = new Object(); static int i = 0; public void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { synchronized (OBJECT) { increase(); } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AccountingSync()); Thread t2 = new Thread(new AccountingSync()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
Das synchronisierte Schlüsselwort wirkt sich auf Instanzmethoden aus, was bedeutet, dass der Thread vor dem Aufrufen der raise()-Methode die Sperre der aktuellen Instanz erhalten muss. Dies erfordert, dass wir beim Erstellen einer Thread-Instanz dieselbe ausführbare Objektinstanz verwenden , die Thread-Sperren befinden sich nicht auf derselben Instanz und es gibt keine Möglichkeit, über Sperr-/Synchronisierungsprobleme zu sprechen.
Bitte beachten Sie Präfix der Hauptmethode. Drei Zeilen, die die korrekte Verwendung von Schlüsselwörtern für Instanzmethoden erläutern.
public class AccountingSync implements Runnable { static int i = 0; public synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { AccountingSync accountingSync = new AccountingSync(); Thread t1 = new Thread(accountingSync); Thread t2 = new Thread(accountingSync); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
2.3 Direktes Einwirken auf statische Methoden
Verwenden Sie das synchronisierte Schlüsselwort für statische Methoden Dies ist nicht erforderlich. Im Beispiel müssen zwei Threads auf dieselbe Runnable-Methode verweisen. Da der Methodenblock die Sperre der aktuellen Klasse und nicht der aktuellen Instanz anfordern muss, können die Threads weiterhin korrekt synchronisiert werden 🎜>
public class AccountingSync implements Runnable { static int i = 0; public static synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 1000000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AccountingSync()); Thread t2 = new Thread(new AccountingSync()); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
public class BadLockOnInteger implements Runnable { static Integer i = 0; @Override public void run() { for (int j = 0; j < 1000000; j++) { synchronized (i) { i++; } } } public static void main(String[] args) throws InterruptedException { BadLockOnInteger badLockOnInteger = new BadLockOnInteger(); Thread t1 = new Thread(badLockOnInteger); Thread t2 = new Thread(badLockOnInteger); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
Weitere Artikel zur Verwendung von Java-synchronisierten Schlüsselwörtern finden Sie auf der chinesischen PHP-Website!