1. Wenn es häufig zu Sperrenkonflikten kommt, wird es zu einer pessimistischen Sperrung umgewandelt Eine lange, lange Zeit, es wird in eine Schwergewichtssperre umgewandelt.
3 Die Spin-Lock-Strategie, die am häufigsten bei der Implementierung von Leichtgewichtssperren verwendet wird
6. Keine Lese-/Schreibsperre2. Der SperrprozessJVM unterteilt synchronisierte Sperren in sperrenfreie, voreingenommene Sperren, leichte Sperren und schwere Sperren. Es wird je nach Situation nacheinander aktualisiert.Angenommen, der männliche Protagonist ist ein Schloss und der weibliche Protagonist ist ein Thread. Wenn es nur einen Thread gibt, um dieses Schloss zu verwenden, dann erhalten der männliche Protagonist und der weibliche Protagonist keinen Thread Heiratsurkunde (Vermeidung kostenintensiver Operationen), aber die weibliche Protagonistin erscheint und versucht, um die männliche Protagonistin zu konkurrieren, egal wie teuer die Operation, eine Heiratsurkunde zu bekommen, ist Diese Aktion muss abgeschlossen werden, wodurch die weibliche Protagonistin aufgibt
Die Voreingenommenheit besteht nicht darin, zu sperren. Beim „Sperren“ geht es lediglich darum, im Objektheader eine „Sperrvoreingenommenheitsmarkierung“ zu erstellen, um aufzuzeichnen, zu welchem Thread die Sperre gehört Wenn später keine anderen Threads um die Sperre konkurrieren, müssen keine weiteren Synchronisierungsvorgänge durchgeführt werden (wodurch die Notwendigkeit des Hinzufügens von Sperren vermieden wird). Wenn es später andere Threads gibt, die um die Sperre konkurrieren (welcher Thread). Die aktuelle Sperre wurde im Sperrobjekt aufgezeichnet. Es ist leicht zu erkennen, ob der Thread, der die Sperre derzeit anwendet, der zuvor aufgezeichnete Thread ist. Anschließend wird der ursprüngliche voreingenommene Sperrzustand abgebrochen, der in den allgemeinen leichten Sperrzustand übergeht
Voreingenommen Sperren ist im Wesentlichen gleichbedeutend mit „verzögertem Sperren“. Wenn Sie es nicht sperren können, sperren Sie es nicht und versuchen Sie, unnötigen Sperraufwand zu vermeiden. Es muss jedoch noch eine Markierung vorgenommen werden, da dies sonst nicht möglich ist Unterscheiden Sie, wann eine echte Sperre erforderlich ist. Eine voreingenommene Sperre ist keine wirkliche Sperre, sondern zeichnet nur eine Markierung im Objektheader der Sperre auf (Aufzeichnung des Threads, zu dem die Sperre gehört. Wenn keine anderen Threads an konkurrierenden Sperren beteiligt sind, erfolgt der Sperrvorgang). wird nicht tatsächlich ausgeführt, wodurch der Programmaufwand verringert wird. Sobald andere Threads wirklich am Wettbewerb beteiligt sind, wird der voreingenommene Sperrzustand aufgehoben und in den leichten Sperrzustand versetzt Der voreingenommene Sperrzustand wird eliminiert und der leichte Sperrzustand (adaptive Spin-Sperre) wird hier über CAS implementiert. Überprüfen und aktualisieren Sie einen Teil des Speichers über CAS (z. B. null => Von diesem Thread referenziert). )Wenn das Update erfolgreich ist, gilt die Sperre als erfolgreich.Wenn das Update fehlschlägt, gilt die Sperre als belegt und das spinartige Warten wird fortgesetzt (ohne die CPU aufzugeben).Der Spin-Vorgang behält die CPU bei Der Leerlauf ist eine Verschwendung von CPU-Ressourcen. Daher wird die Drehung hier nicht ewig fortgesetzt, sondern nach Erreichen einer bestimmten Zeit/Anzahl von Wiederholungsversuchen gestoppt. Dies ist die sogenannte „adaptive“ Sperre Wenn der Spin intensiver wird und den Sperrstatus nicht schnell erreichen kann, wird er zu einer Schwergewichtssperre erweitert. Die Schwergewichtssperre bezieht sich hier auf die Verwendung des vom Kernel bereitgestellten Mutex. Um den Sperrvorgang durchzuführen, geben Sie den ersten Kernel-Status ein. Bestimmen Sie, ob die aktuelle Sperre im Kernel-Status belegt ist.Wenn die Sperre nicht belegt ist, ist die Sperre erfolgreich und der Schalter kehrt in den Benutzerstatus zurück.Wenn die Sperre belegt ist, schlägt die Sperre fehl Diesmal wird der Thread in die Warteschlange der Sperre eingefügt und wartet darauf, vom Betriebssystem geweckt zu werden. Nach einer Reihe von Änderungen wurde die Sperre auch von anderen Threads aufgehoben Es hat den Thread aufgeweckt und versucht, die Sperre neu zu starten Anwendungscodes werden synchronisiert, aber in einer Thread-Umgebung (wie StringBuffer) wird es tatsächlich nicht verwendet Wenn es sich um einen einzelnen Thread handelt, sind diese Sperr- und Entsperrvorgänge unnötig und verschwenden einen gewissen Ressourcenaufwand Leiter, Arbeitsaufgaben an Untergebene zuweisenMethode 1:Anrufen, Aufgabe 1 geben, auflegen.Anrufen, Aufgabe 2 geben, auflegen.Anrufen, Aufgabe 3 geben, auflegenMethode 2 :Rufen Sie an, geben Sie Aufgabe 1, Aufgabe 2, Aufgabe 3 ein, legen Sie den Hörer auf. Was ist Callable? Callable ist eine Schnittstelle Thread. Für Programmierer ist es praktisch, Ergebnisse mithilfe von Multithreading zu berechnen.Callable 和 Runnable 相对, 都是描述一个 "任务". Callable 描述的是带有返回值的任务, Runnable 描述的是不带返回值的任务.Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为 Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定. FutureTask 就可以负责这个等待结果出来的工作.
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 不使用 Callable 版本
public class Text { static class Result{ public int sum = 0; public Object locker = new Object(); } public static void main(String[] args) throws InterruptedException { Result result = new Result(); Thread t = new Thread(){ @Override public void run() { int sum = 0; for (int i = 0; i <=10000; i++){ sum += i; } result.sum = sum; synchronized (result.locker){ result.locker.notify(); } } }; t.start(); synchronized (result.locker){ while (result.sum == 0){ result.locker.wait(); } } System.out.println(result.sum); } }
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 使用 Callable 版本
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Text1 { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <=1000; i++){ sum += i; } return sum; } }; //由于Thread不能直接传一个callable实例,就需要一个辅助类来包装 FutureTask<Integer> futureTask = new FutureTask<>(callable); Thread t = new Thread(futureTask); t.start(); //尝试在主线程获取结果 //如果FutureTask中的结果还没生成。此时就会阻塞等待 //一直等到最终的线程把这个结果算出来,get返回 Integer result = futureTask.get(); System.out.println(result); } }
Das obige ist der detaillierte Inhalt vonDie Prinzipien und Nutzungsszenarien von Synchronized in Java sowie die Nutzungs- und Differenzanalyse der Callable-Schnittstelle. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!