web-dev-qa-db-de.com

Verwenden Sie jemals das volatile Keyword in Java?

Bei der Arbeit bin ich heute in Java auf das volatile-Schlüsselwort gestoßen. Ich kannte mich nicht so gut aus und fand diese Erklärung: 

Java Theorie und Praxis: Volatilität managen

Verwenden Sie angesichts der Details, in denen der Artikel das betreffende Keyword erläutert, Sie es oder verwenden Sie einen Fall, in dem Sie dieses Keyword in der richtigen Weise verwenden könnten?

565
Richard

volatile hat eine Semantik für die Sichtbarkeit des Speichers. Grundsätzlich wird der Wert eines volatile-Feldes für alle Leser (insbesondere andere Threads) sichtbar, nachdem eine Schreiboperation darauf abgeschlossen wurde. Ohne volatile könnten Leser einen nicht aktualisierten Wert sehen.

Um Ihre Frage zu beantworten: Ja, ich verwende eine Variable volatile, um zu steuern, ob ein Code eine Schleife fortsetzt. Die Schleife testet den volatile-Wert und fährt fort, wenn es true ist. Die Bedingung kann durch Aufruf einer "stop" -Methode auf false gesetzt werden. Die Schleife sieht false und endet, wenn sie den Wert testet, nachdem die stop-Methode die Ausführung abgeschlossen hat.

Das Buch " Java Concurrency in Practice ", das ich sehr empfehle, gibt eine gute Erklärung von volatile. Dieses Buch wurde von derselben Person verfasst, die den IBM-Artikel verfasst hat, auf den in der Frage verwiesen wird (er zitiert sein Buch am Ende dieses Artikels). volatile benutze ich in seinem Artikel als "Status-Flag" von Muster 1.

Wenn Sie mehr darüber erfahren möchten, wie volatile unter der Haube arbeitet, lesen Sie das das Java-Speichermodell . Wenn Sie über dieses Niveau hinausgehen möchten, lesen Sie ein gutes Computerarchitekturbuch wie Hennessy & Patterson und informieren Sie sich über Cache-Kohärenz und Cache-Konsistenz.

670
Greg Mattes

"... der flüchtige Modifizierer garantiert, dass jeder Thread, der ein Feld liest, den zuletzt geschriebenen Wert sieht."- Josh Bloch

Wenn Sie über die Verwendung von volatile nachdenken, lesen Sie das Paket Java.util.concurrent , das sich mit atomarem Verhalten befasst.

Der Wikipedia-Beitrag zu einem Singleton-Muster zeigt die Volatilität im Gebrauch.

156
Ande TURNER

Wichtiger Punkt zu volatile: 

  1. Die Synchronisierung in Java ist mit den Java-Schlüsselwörtern synchronized und volatile und mit Sperren möglich.
  2. In Java können wir keine Variable synchronized haben. Die Verwendung des synchronized-Schlüsselworts mit einer Variablen ist illegal und führt zu einem Kompilierungsfehler. Anstatt die Variable synchronized in Java zu verwenden, können Sie die Java-Variable volatile verwenden, die JVM-Threads anweist, den Wert der Variable volatile aus dem Hauptspeicher zu lesen und nicht lokal zu speichern.
  3. Wenn eine Variable nicht von mehreren Threads gemeinsam genutzt wird, muss das Schlüsselwort volatile nicht verwendet werden.

Quelle

Beispiel für die Verwendung von volatile:

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

Wir erstellen die Instanz zu dem Zeitpunkt, zu dem die erste Anfrage kommt.

Wenn wir die _instance-Variable volatile nicht erstellen, kann der Thread, der die Instanz von Singleton erstellt, nicht mit dem anderen Thread kommunizieren. Wenn Thread A die Singleton-Instanz erstellt und kurz nach der Erstellung die CPU usw. beschädigt, können alle anderen Threads den Wert von _instance nicht als nicht-null sehen und glauben, dass ihm noch null zugewiesen wird. 

Warum passiert das? Da Reader-Threads nicht gesperrt werden und der Writer-Thread nicht aus einem synchronisierten Block kommt, wird der Speicher nicht synchronisiert und der Wert von _instance wird nicht im Hauptspeicher aktualisiert. Mit dem Schlüsselwort "Volatile" in Java wird dies von Java selbst gehandhabt. Solche Aktualisierungen sind für alle Leser-Threads sichtbar. 

Conclusion: Das volatile-Schlüsselwort wird auch verwendet, um den Speicherinhalt zwischen Threads zu kommunizieren. 

Beispiel für die Verwendung von "volatil":

public class Singleton{    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance(){   
          if(_instance == null){  
              synchronized(Singleton.class){  
               if(_instance == null) _instance = new Singleton(); 
      } 
     }   
    return _instance;  
    }

Der obige Code ist nicht threadsicher. Obwohl der Wert der Instanz innerhalb des synchronisierten Blocks erneut überprüft wird (aus Performancegründen), kann der JIT-Compiler den Bytecode so anordnen, dass die Referenz auf die Instanz festgelegt wird, bevor der Konstruktor seine Ausführung beendet hat. Dies bedeutet, dass die Methode getInstance () ein Objekt zurückgibt, das möglicherweise nicht vollständig initialisiert wurde. Um den Code threadsicher zu machen, kann das Schlüsselwort volatile seit Java 5 für die Instanzvariable verwendet werden. Variablen, die als flüchtig markiert sind, werden nur für andere Threads sichtbar, wenn der Konstruktor des Objekts seine Ausführung vollständig abgeschlossen hat.
Quelle

 enter image description here

volatile Verwendung in Java:

Die Fail-Fast-Iteratoren werden normalerweise implementiert, indem ein volatile-Zähler für das Listenobjekt verwendet wird.

  • Wenn die Liste aktualisiert wird, wird der Zähler inkrementiert. 
  • Bei der Erstellung einer Iterator wird der aktuelle Wert des Zählers in das Iterator-Objekt eingebettet.
  • Wenn eine Iterator-Operation ausgeführt wird, vergleicht die Methode die beiden Zählerwerte und wirft eine ConcurrentModificationException, falls sie unterschiedlich sind.

Die Implementierung von fehlersicheren Iteratoren ist normalerweise leicht. Sie sind normalerweise auf Eigenschaften der Datenstrukturen der spezifischen Listenimplementierung angewiesen. Es gibt kein allgemeines Muster. 

95
Premraj

volatile ist sehr nützlich, um Threads zu stoppen.

Nicht dass Sie Ihre eigenen Threads schreiben sollten, Java 1.6 hat viele Nice-Thread-Pools. Wenn Sie jedoch sicher sind, dass Sie einen Thread benötigen, müssen Sie wissen, wie Sie ihn stoppen können.

Das Muster, das ich für Threads verwende, ist:

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

Beachten Sie, dass keine Synchronisierung erforderlich ist

49
Pyrolistical

Ein übliches Beispiel für die Verwendung von volatile ist die Verwendung einer volatile boolean-Variablen als Flag zum Beenden eines Threads. Wenn Sie einen Thread gestartet haben und ihn von einem anderen Thread aus sicher unterbrechen können, können Sie ihn regelmäßig von einem Thread überprüfen lassen. Setzen Sie das Flag auf true, um es zu stoppen. Durch das Setzen des Flags volatile können Sie sicherstellen, dass der Thread, der überprüft wird, bei der nächsten Überprüfung als gesetzt angezeigt wird, ohne einen synchronized-Block zu verwenden.

30
Dave L.

Niemand hat die Behandlung von Lese- und Schreiboperationen für lange und doppelte Variablentypen erwähnt. Lese- und Schreibvorgänge sind atomare Operationen für Referenzvariablen und für die meisten primitiven Variablen, mit Ausnahme der Typen für lange und doppelte Variablen, die das volatile-Schlüsselwort als atomare Operationen verwenden müssen. @Verknüpfung

12

Ja, volatile muss verwendet werden, wenn Sie möchten, dass mehrere Variablen auf eine veränderliche Variable zugreifen. Dies ist nicht sehr üblich, da Sie normalerweise mehr als eine einzelne atomare Operation durchführen müssen (beispielsweise den Status der Variablen überprüfen, bevor Sie sie ändern). In diesem Fall würden Sie stattdessen einen synchronisierten Block verwenden.

12
ykaganovich

Eine mit dem Schlüsselwort volatile deklarierte Variable hat zwei Hauptqualitäten, die sie besonders machen.

  1. Wenn wir eine flüchtige Variable haben, kann sie von keinem Thread in den Cache-Speicher des Computers (Mikroprozessor) zwischengespeichert werden. Der Zugriff erfolgte immer aus dem Hauptspeicher.

  2. Wenn eineSchreiboperationauf eine flüchtige Variable geht und plötzlich eineLeseoperationangefordert wird, ist garantiert, dass dieSchreibvorgang wird vor dem Lesevorgang beendet.

Zwei oben genannte Qualitäten leiten das ab

  • Alle Threads, die eine flüchtige Variable lesen, lesen auf jeden Fall den neuesten Wert. Weil kein zwischengespeicherter Wert ihn verschmutzen kann. Und auch die Leseanforderung wird erst nach Abschluss des aktuellen Schreibvorgangs erteilt.

Und auf der anderen Seite

  • Wenn wir das von mir erwähnte # 2 genauer untersuchen, können wir feststellen, dass das volatile-Schlüsselwort eine ideale Methode ist, um eine gemeinsam genutzte Variable zu verwalten, die'n' Anzahl der Lese-Threads und nur einen Schreib-Thread hat, um darauf zuzugreifen. Sobald wir das Schlüsselwort volatile hinzugefügt haben, ist es fertig. Kein anderer Aufwand zur Gewindesicherheit.

Umgekehrt 

Wirkönnen nichtverwenden ausschließlich das volatile-Schlüsselwort, um eine gemeinsam genutzte Variable zu erfüllen, diemehrere Schreib-Threads, die darauf zugreifen.

11

IMO sind zwei wichtige Szenarien außer dem Stoppen des Threads, in dem volatile Keywords verwendet werden 

  1. Doppelter Karussellmechanismus . Wird häufig im Singleton-Design Pattern verwendet. In diesem ist der singleton object needs to be declared volatile.
  2. Sporadisches Aufwachen . Der Thread kann manchmal aus dem Warteanruf aufgeweckt werden, auch wenn kein Benachrichtigungsanruf ausgegeben wurde. Dieses Verhalten wird als unauffälliges Aufwachen bezeichnet. Dem kann durch Verwendung einer bedingten Variablen (boolesches Flag) begegnet werden. Platzieren Sie den wait () - Aufruf in einer while-Schleife, solange das Flag wahr ist. Wenn der Thread also aus anderen Gründen als notify/notifyall aus dem wait-Aufruf aufwacht, wird festgestellt, dass das Flag immer noch wahr ist, und Aufrufe warten daher erneut. Setzen Sie dieses Kennzeichen vor dem Aufruf der Benachrichtigung auf true. In diesem Fall den boolean flag is declared as volatile.
9
Aniket Thakur

volatile garantiert nur, dass alle Threads, auch sie selbst, inkrementieren. Zum Beispiel: Ein Zähler sieht gleichzeitig das gleiche Gesicht der Variablen. Es wird nicht anstelle von synchronisiertem oder atomarem oder anderem Zeug verwendet, sondern macht die Lesevorgänge vollständig synchronisiert. Vergleichen Sie es nicht mit anderen Java-Schlüsselwörtern. Wie das Beispiel unten zeigt, sind volatile variable Operationen auch atomar, sie schlagen fehl oder sind sofort erfolgreich.

package io.netty.example.telnet;

import Java.util.ArrayList;
import Java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Selbst wenn Sie unbeständige Ergebnisse erzielen oder nicht, werden die Ergebnisse immer unterschiedlich sein. Wenn Sie jedoch AtomicInteger als unten verwenden, werden die Ergebnisse immer gleich sein. Dies gilt auch für synchronisiert.

    package io.netty.example.telnet;

    import Java.util.ArrayList;
    import Java.util.List;
    import Java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }
5
fatih tekin

Wenn Sie eine Multithread-Anwendung entwickeln, müssen Sie das Schlüsselwort "volatile" oder "synchronized" und alle anderen verfügbaren Tools und Techniken für die Steuerung der Parallelität verwenden. Ein Beispiel für eine solche Anwendung sind Desktop-Apps.

Wenn Sie eine Anwendung entwickeln, die auf einem Anwendungsserver bereitgestellt wird (Tomcat, JBoss AS, Glassfish usw.), müssen Sie die Parallelitätskontrolle nicht selbst übernehmen, da sie bereits vom Anwendungsserver adressiert wird. Wenn ich mich richtig erinnere, verbietet der Java EE-Standard die gleichzeitige Steuerung von Servlets und EJBs, da er Teil der "Infrastruktur" -Ebene ist, die Sie für die Handhabung freigeben sollten. Sie steuern nur die Parallelität in einer solchen App, wenn Sie Einzelobjekte implementieren. Dies wurde auch schon angesprochen, wenn Sie Ihre Komponenten mit einem Framework wie Spring stricken.

In den meisten Fällen der Java-Entwicklung, bei denen es sich bei der Anwendung um eine Webanwendung handelt und IoC-Framework wie Spring oder EJB verwendet, müssen Sie nicht 'flüchtig' verwenden.

5
Rudi Adianto

Ja, ich benutze es oft - es kann sehr nützlich sein für Multithreadcode. Der Artikel, auf den Sie hingewiesen haben, ist gut. Obwohl es zwei wichtige Dinge zu beachten gibt:

  1. Sie sollten Volatile nur verwenden, wenn Sie Vollständig verstanden haben, was es__ tut und wie es sich von synchronisiert unterscheidet. In vielen Situationen scheint es flüchtig zu sein, an der Oberfläche eine einfachere, performantere Alternative zu Synchronisation zu sein, wenn oft ein besseres Verständnis von Unbeständigem klar machen würde ist die einzige Option .__, die funktionieren würde.
  2. volatile funktioniert nicht in einer Menge älterer JVMs, obwohl synchronized funktioniert. Ich erinnere mich, dass ich ein Dokument gesehen habe, das auf die verschiedenen Unterstützungsniveaus in verschiedenen JVMs verwies, aber leider kann ich es jetzt nicht finden. Informieren Sie sich auf jeden Fall, wenn Sie Java vor 1.5 verwenden oder wenn Sie keine Kontrolle über die JVMs haben, auf denen Ihr Programm ausgeführt wird.
4
MB.

Absolut ja. (Und nicht nur in Java, sondern auch in C #.) Es gibt Situationen, in denen Sie einen Wert abrufen oder festlegen müssen, der zwar auf Ihrer Plattform als atomarer Vorgang gilt, beispielsweise ein int oder ein booleaner Wert, der jedoch nicht erforderlich ist der Aufwand für die Gewindesicherung. Mit dem volatile-Schlüsselwort können Sie sicherstellen, dass beim Lesen des Werts der Wert current und nicht ein zwischengespeicherter Wert abgerufen wird, der gerade durch einen Schreibvorgang in einem anderen Thread veraltet wurde.

3
dgvid

Jeder Thread, der auf ein flüchtiges Feld zugreift, liest seinen aktuellen Wert, bevor er fortfährt, anstatt (möglicherweise) einen zwischengespeicherten Wert zu verwenden.

Nur die Elementvariable kann flüchtig oder flüchtig sein.

3
tstuber

Es gibt zwei verschiedene Verwendungsmöglichkeiten für volatile Keywords.

  1. Verhindert, dass die JVM Werte aus dem Register liest (als Cache annehmen), und zwingt ihren Wert, aus dem Speicher zu lesen.
  2. Reduziert das Risiko von Konsistenzfehlern im Arbeitsspeicher.

Verhindert, dass die JVM Werte im Register liest, und erzwingt deren Wert, der aus dem Speicher gelesen werden soll.

Ein busy flag wird verwendet, um zu verhindern, dass ein Thread fortgesetzt wird, während das Gerät beschäftigt ist und das Flag nicht durch eine Sperre geschützt ist:

while (busy) {
    /* do something else */
}

Der Testthread wird fortgesetzt, wenn ein anderer Thread das Besetzt-Flagdeaktiviert. _:

busy = 0;

Da jedoch in dem Test-Thread häufig auf Beschäftigte zugegriffen wird, kann die JVM den Test optimieren, indem sie den Wert von beschäftigt in ein Register legt und dann den Inhalt des Registers testet, ohne den Wert von beschäftigt im Speicher vor jedem Test zu lesen. Der Test-Thread würde nie eine Änderung für beschäftigt sehen, und der andere Thread würde nur den Wert von beschäftigt im Arbeitsspeicher ändern, was zu einem Deadlock führt. Wenn Sie das busy flag als flüchtig deklarieren, wird der Wert vor jedem Test gelesen.

Reduziert das Risiko von Speicherkonsistenzfehlern.

Die Verwendung flüchtiger Variablen verringert das Risiko von Speicher-Konsistenzfehlern , da bei jedem Schreibvorgang in eine flüchtige Variable eine Beziehung von "passiert vor" mit nachfolgenden Lesevorgängen derselben Variablen hergestellt wird. Das bedeutet, dass Änderungen an einer flüchtigen Variablen für andere Threads immer sichtbar sind.

Die Technik des Lesens und Schreibens ohne Speicherkonsistenzfehler wird als atomische Aktion bezeichnet.

Eine atomare Aktion ist eine, die effektiv alle gleichzeitig geschieht. Eine atomare Aktion kann nicht in der Mitte aufhören: entweder vollständig oder gar nicht. Es sind keine Nebenwirkungen einer atomaren Aktion sichtbar, bis die Aktion abgeschlossen ist.

Nachfolgend sind die Aktionen aufgeführt, die Sie festlegen können, die atomar sind:

  • Lese- und Schreibvorgänge sind atomar für Referenzvariablen und für die meisten Primitivvariablen (alle Typen außer long und double).
  • Lese- und Schreibvorgänge sind für alle deklarierten Variablen volatile (Einschließlich langer und doppelter Variablen) atomar.

Prost!

2
dheeran

Volatile macht folgendes.

1> Das Lesen und Schreiben von flüchtigen Variablen durch verschiedene Threads erfolgt immer aus dem Speicher, nicht aus dem eigenen Cache oder dem CPU-Register des Threads. Jeder Thread behandelt also immer den neuesten Wert. 2> Wenn zwei verschiedene Threads mit derselben Instanz oder statischen Variablen im Heap arbeiten, werden die Aktionen des anderen möglicherweise als nicht in der richtigen Reihenfolge angezeigt. Siehe den Blog von Jeremy Manson. Flüchtig hilft hier aber.

Der folgende vollständig ausgeführte Code zeigt, wie eine Reihe von Threads in vordefinierter Reihenfolge und Druckausgaben ausgeführt werden können, ohne ein synchronisiertes Schlüsselwort zu verwenden.

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

Um dies zu erreichen, können wir den folgenden voll ausgeführten Laufcode verwenden.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

Der folgende Github-Link enthält eine Readme-Datei, die eine entsprechende Erklärung enthält . https://github.com/sankar4git/volatile_thread_ordering

2
sankar banerjee

Flüchtige Variablen sind leichtgewichtige Synchronisation. Wenn die Sichtbarkeit der neuesten Daten zwischen allen Threads erforderlich ist und die Atomizität beeinträchtigt werden kann, müssen in solchen Situationen flüchtige Variablen bevorzugt werden. Read on volatile-Variablen geben immer den neuesten Schreibvorgang eines Threads zurück, da sie weder in Registern gespeichert werden, noch in Caches, wo andere Prozessoren sie nicht sehen können. Flüchtig ist Lock-Free. Ich verwende Volatile, wenn das Szenario die oben genannten Kriterien erfüllt. 

2
Neha Vari

Aus der Oracle-Dokumentation page ergibt sich die Notwendigkeit einer flüchtigen Variablen, um Konsistenzprobleme zu beheben:

Durch die Verwendung flüchtiger Variablen wird das Risiko von Speicherkonsistenzfehlern verringert, da durch das Schreiben in eine flüchtige Variable eine Ereignis-Vorher-Beziehung mit nachfolgenden Lesevorgängen derselben Variablen hergestellt wird. 

Dies bedeutet, dass Änderungen an einer Variablen mit dem Namen volatile für andere Threads immer sichtbar sind. Dies bedeutet auch, dass ein Thread, wenn er eine flüchtige Variable liest, nicht nur die letzte Änderung an volatile, sondern auch die Nebenwirkungen des Codes erkennt, der die Änderung ausgelöst hat.

Wie in Peter Parker answer erläutert, kann der Stack jedes Threads in Abwesenheit des Moduls volatile eine eigene Kopie der Variablen haben. Wenn Sie die Variable als volatile festlegen, wurden Probleme mit der Speicherkonsistenz behoben. 

Werfen Sie einen Blick auf jenkov Tutorial-Seite zum besseren Verständnis. 

Sehen Sie sich die verwandte SE-Frage an, um weitere Informationen zu volatilen und Anwendungsfällen für die Verwendung von volatil zu erhalten:

Unterschied zwischen flüchtig und synchronisiert in Java

Ein praktischer Anwendungsfall:

Sie haben viele Threads, die zum Beispiel die aktuelle Uhrzeit in einem bestimmten Format drucken müssen: Java.text.SimpleDateFormat("HH-mm-ss"). Sie können eine Klasse haben, die die aktuelle Uhrzeit in SimpleDateFormat umwandelt und die Variable jede Sekunde aktualisiert. Alle anderen Threads können diese flüchtige Variable einfach verwenden, um die aktuelle Uhrzeit in Protokolldateien zu drucken. 

1
Ravindra babu

Nachfolgend finden Sie einen sehr einfachen Code, um die Anforderung von volatile zu demonstrieren.

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

Wenn volatile nicht verwendet wird: wird auch nach 'Stopping on: xxx' niemals die Meldung 'Stopped am: xxx' angezeigt, und das Programm läuft weiter.

Stopping on: 1895303906650500

Wenn volatile verwendet wird: wird sofort das 'Stopped am: xxx' angezeigt.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300
0
manikanta

Wenn der flüchtige Schlüssel mit einer Variablen verwendet wird, wird sichergestellt, dass Threads, die diese Variable lesen, denselben Wert sehen. Wenn Sie jetzt mehrere Threads lesen und in eine Variable schreiben, reicht es nicht aus, die Variable flüchtig zu machen, und die Daten werden beschädigt. Bild-Threads haben denselben Wert gelesen, aber jeder hat einige Änderungen vorgenommen (beispielsweise einen Zähler inkrementiert). Beim Zurückschreiben in den Speicher wird die Datenintegrität verletzt. Deshalb ist es notwendig, die Variablen synchron zu machen (verschiedene Wege sind möglich)

Wenn die Änderungen von einem Thread durchgeführt werden und die anderen nur diesen Wert lesen müssen, ist der Volatilwert geeignet.

0
Java Main

Eine Volatile-Variable wird asynchron durch gleichzeitiges Ausführen von Threads in einer Java-Anwendung geändert. Es ist nicht zulässig, eine lokale Kopie einer Variablen zu haben, die sich von dem aktuell im "Hauptspeicher" gespeicherten Wert unterscheidet. In der Tat muss für eine für volatile deklarierte Variable die Daten über alle Threads hinweg synchronisiert werden. Wenn Sie also auf die Variable in einem beliebigen Thread zugreifen oder sie aktualisieren, wird für alle anderen Threads sofort derselbe Wert angezeigt. Natürlich ist es wahrscheinlich, dass flüchtige Variablen einen höheren Zugriffs- und Aktualisierungsaufwand haben als "einfache" Variablen, da Threads eine eigene Datenkopie haben können, um die Effizienz zu erhöhen.

Wenn ein Feld für flüchtig erklärt wird, werden der Compiler und die Laufzeitumgebung darauf aufmerksam gemacht, dass diese Variable gemeinsam genutzt wird und diese Operationen nicht mit anderen Speicheroperationen neu angeordnet werden sollten. Flüchtige Variablen werden nicht in Registern oder in Caches zwischengespeichert, in denen sie vor anderen verborgen sind Prozessoren, so dass ein Lesen einer flüchtigen Variablen immer den letzten Schreibvorgang durch einen beliebigen Thread zurückgibt.

weitere Informationen finden Sie hier http://techno-terminal.blogspot.in/2015/11/what-are-volatile-variables.html

0
satish

die flüchtige Variable wird im Grunde genommen für die sofortige Aktualisierung (Flush) der gemeinsamen Cache-Hauptzeile verwendet, sobald sie aktualisiert wurde, sodass Änderungen sofort für alle Worker-Threads wirksam werden.

0
Niyaz Ahamad

Ich mag Jenkovs Erklärung :

Das Schlüsselwort Java volatile kennzeichnet eine Java-Variable als "im Hauptspeicher gespeichert". Genauer gesagt bedeutet dies, dass jeder Lesevorgang einer flüchtigen Variablen aus dem Hauptspeicher des Computers und nicht aus dem CPU-Cache gelesen wird und dass jeder Schreibvorgang in eine flüchtige Variable in den Hauptspeicher geschrieben wird und nicht nur in den CPU-Cache .

Tatsächlich garantiert das volatile Keyword seit Java 5 mehr als nur das flüchtige Variablen werden in den Hauptspeicher geschrieben und aus diesem gelesen. 

Es handelt sich um eine erweiterte Sichtbarkeitsgarantie, die so genannte "done-before" -Garantie.

Leistungsaspekte von Volatilität

Beim Lesen und Schreiben flüchtiger Variablen wird die Variable gelesen oder in den Hauptspeicher geschrieben. Das Lesen und Schreiben in den Hauptspeicher ist teurer als der Zugriff auf den CPU-Cache. Durch den Zugriff auf flüchtige Variablen wird auch die Neuordnung von Befehlen verhindert, was eine normale Technik zur Leistungssteigerung ist. Daher sollten Sie nur flüchtige Variablen verwenden, wenn Sie die Sichtbarkeit von Variablen wirklich erzwingen müssen.

0
yoAlex5