Heim  >  Artikel  >  Java  >  Garantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?

Garantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?

王林
王林nach vorne
2023-04-21 20:07:062897Durchsuche

volatile

volatile ist ein relativ wichtiges Schlüsselwort in Java. Es wird hauptsächlich zum Ändern von Variablen verwendet, auf die von verschiedenen Threads zugegriffen und diese geändert werden.

Und diese Variable kann nur zwei Eigenschaften garantieren: Die eine dient der Gewährleistung der Ordnung und die andere der Gewährleistung der Sichtbarkeit.

Was ist also Ordnung und was ist Sichtbarkeit?

Ordnung

Was ist also Ordnung?

Tatsächlich basiert die Reihenfolge der Programmausführung auf der Reihenfolge des Codes, und eine Neuordnung der Anweisungen ist verboten.

Es scheint natürlich, aber es ist nicht so, dass die JVM Anweisungen optimiert, die Effizienz der Programmausführung verbessert und die Parallelität so weit wie möglich erhöht, ohne die Ausführungsergebnisse von Single-Thread-Programmen zu beeinträchtigen.

Aber in der 多线程-Umgebung ändert sich die Reihenfolge einiger Codes, was zu logischen Fehlern führen kann.

Und volatile ist für diese Funktion bekannt.

volatile Wie sorgt man für Ordnung?

Viele Freunde sagten, dass Volatilität die Neuordnung von Anweisungen verhindern kann, wodurch sichergestellt wird, dass das Codeprogramm strikt in der Reihenfolge des Codes ausgeführt wird. Das sorgt für Ordnung. Die Operationen an durch flüchtig geänderten Variablen werden streng in der Reihenfolge des Codes ausgeführt. Das heißt, wenn der Code an der durch flüchtig geänderten Variablen ausgeführt wird, muss der vorherige Code ausgeführt werden und der folgende Code darf nicht ausgeführt werden .

Wenn der Interviewer zu diesem Zeitpunkt nicht weiter nachforscht, dann herzlichen Glückwunsch. Vielleicht wurde diese Frage beantwortet, aber wenn der Interviewer weiter nachforscht, warum ist die Neuanordnung der Befehle verboten? Neuordnung?

Die Ausführung vom Quellcode zu Anweisungen ist im Allgemeinen in drei Neuanordnungen unterteilt, wie in der Abbildung dargestellt:

Als nächstes müssen wir uns ansehen, wie flüchtig Befehle verboten sind Neuordnung.

Garantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?

Wir verwenden den Code direkt zur Überprüfung:

public class ReSortDemo {

int a = 0;
boolean flag = false;

public void mehtod1(){
a = 1;
flag = true;
}

public void method2(){
if(flag){
a = a +1;
System.out.println("最后的值: "+a);
}
}
}

Wenn jemand diesen Code sieht, wird er auf jeden Fall sagen, dann kommt dieser Code heraus Was wird das Ergebnis sein? Manche Leute sagen, es sei 2. Ja, wenn Sie es nur in einem einzelnen Thread aufrufen, ist das Ergebnis 2, aber wenn es in mehreren Threads aufgerufen wird, ist das endgültige Ausgabeergebnis nicht unbedingt 2 Wir haben es uns vorgestellt, dann müssen beide Variablen auf flüchtig gesetzt werden.

Wenn Sie mehr über den Singleton-Modus wissen, müssen Sie auf dieses flüchtige Warum geachtet haben.

Sehen Sie sich den folgenden Code an:

class Singleton {
// 不是一个原子性操作
//private static Singleton instance;
//改进,Volatile 可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!
private static volatile Singleton instance;

// 构造器私有化
private Singleton() {
}

// 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题,同时保证了效率, 推荐使用
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

Kennen Sie das obige Singleton-Muster?

Ja, das ist **doppelte Prüfung (DCL-Lazy-Style) **Einige Leute werden sagen, dass aufgrund der Existenz von Befehlsneuordnungen doppelte beendet Der Abrufmechanismus ist nicht unbedingt threadsicher, also wird das synchronisierte Schlüsselwort verwendet, um ihn threadsicher zu machen.

Sichtbarkeit

Tatsächlich ist Sichtbarkeit die Frage, ob Änderungen an gemeinsam genutzten Variablen für andere Threads in einer Multithread-Umgebung sofort sichtbar sind.

Wo erscheint also generell seine Sichtbarkeit? Wo wird es verwendet?

Tatsächlich wird diese Variable im Allgemeinen verwendet, hauptsächlich um ihre Sichtbarkeit sicherzustellen, z. B. als globale Variable, in der es eine Schleife gibt, um den Wert dieser Variablen zu bestimmen, und ein Thread diese Parameter ändert , stoppt diese Schleife und springt zur nächsten Ausführung.

Werfen wir einen Blick auf die Code-Implementierung ohne flüchtige Modifikation:

public class Test {

private static boolean flag = false;

public static void main(String[] args) throws Exception{
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程A开始执行:");
for (;;){
if (flag){
System.out.println("跳出循环");
break;
}
}
}
}).start();
Thread.sleep(100);

new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程B开始执行");
flag = true;
System.out.println("标识已经变更");
}
}).start();
}
}

Das Ergebnis ist definitiv so, wie Sie es sich vorstellen können, # 🎜🎜#Das laufende Ergebnis muss sein:

Thread A beginnt mit der Ausführung: Thread B beginnt mit der AusführungDas Logo hat wurde geändert#🎜 🎜#

Tatsächlich, das ist es.



Wenn wir flüchtig verwenden, ist das Ausführungsergebnis dieses Codes dann anders?

Lass es uns versuchen: Garantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?

public class Test {

private static volatile boolean flag = false;

public static void main(String[] args) throws Exception{
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程A开始执行:");
for (;;){
if (flag){
System.out.println("跳出循环");
break;
}
}
}
}).start();
Thread.sleep(100);

new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程B开始执行");
flag = true;
System.out.println("标识已经变更");
}
}).start();
}

Auf diese Weise können wir sehen, dass die Ausgabeanweisung in der Schleife ausgeführt werden kann.

Das heißt, in Thread B ändern wir diese geänderte Variable, und am Ende können wir sie in Thread A reibungslos lesen unsere Daten.

Können wir die Atomizität garantieren? Um die Atomizität aufrechtzuerhalten, sollte das Endergebnis 20000 sein, aber es ist nicht garantiert, dass das Endergebnis jedes Mal 20000 ist, zum Beispiel:

Garantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?#🎜 🎜#

Hauptendzahlenergebnis = 17114#🎜 🎜#Hauptendzahlenergebnis = 20000

Hauptendzahlenergebnis = 19317

Drei Ausführungen, alle mit unterschiedlichen Ergebnisse,

Warum erscheint es? Was ist mit dieser Art? Das hat etwas mit Zahl zu tun++

number++ ist in 3 Anweisungen aufgeteilt

  • Führen Sie GETFIELD aus, um die ursprüngliche Wertzahl im Hauptspeicher abzurufen.

  • Führen Sie IADD aus, um 1 Operation hinzuzufügen. Führen Sie PUTFIELD aus, um den Wert im Arbeitsspeicher zurück in den Arbeitsspeicher zu schreiben Hauptspeicher中

  • Wenn mehrere Threads die PUTFIELD-Anweisung gleichzeitig ausführen, tritt ein Problem beim Zurückschreiben des Hauptspeichers auf, sodass das Endergebnis nicht 20000 ist und Volatilität daher keine Atomizität garantieren kann.

Das obige ist der detaillierte Inhalt vonGarantiert das Schlüsselwort Volatile in Java Thread-Sicherheit?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen