Do czego przydatne jest słowo kluczowe volatile?

Dzisiaj w pracy natknąłem się na volatile słowo kluczowe w Javie. Nie będąc bardzo zaznajomionym z tym, znalazłem to Wyjaśnienie .

Biorąc pod uwagę szczegóły, w których ten artykuł wyjaśnia słowo kluczowe, o którym mowa, czy kiedykolwiek go używasz lub czy kiedykolwiek widzisz przypadek, w którym możesz użyć tego słowa kluczowego we właściwy sposób?

Author: Michael, 2008-09-20

24 answers

volatile posiada semantykę widoczności pamięci. Zasadniczo, wartość pola volatile staje się widoczna dla wszystkich czytelników (w szczególności dla innych wątków) po zakończeniu operacji zapisu na nim. Bez volatile czytelnicy mogli zobaczyć jakąś nie zaktualizowaną wartość.

Aby odpowiedzieć na twoje pytanie: tak, używam zmiennej volatile, aby kontrolować, czy jakiś kod kontynuuje pętlę. Pętla testuje wartość volatile i kontynuuje, jeśli jest to true. Warunek można ustawić na false przez wywołanie metody "stop". Pętla widzi false i kończy się, gdy testuje wartość po zakończeniu wykonywania metody stop.

Książka "współbieżność Javy w praktyce", którą gorąco polecam, daje dobre wyjaśnienie volatile. Ta książka jest napisana przez tę samą osobę, która napisała artykuł IBM, o którym mowa w pytaniu (w rzeczywistości cytuje swoją książkę na dole tego artykułu). Moje użycie volatile jest tym, co jego artykuł nazywa " flagą statusu wzorca 1."

Jeśli chcesz dowiedzieć się więcej o tym, jak volatile Działa pod maską, czytaj na model pamięci Java . Jeśli chcesz wyjść poza ten poziom, sprawdź dobrą książkę o architekturze komputera, taką jak Hennessy & Patterson i przeczytaj o spójności pamięci podręcznej i spójności pamięci podręcznej.

 776
Author: Greg Mattes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 07:44:40

"... modyfikator Lotny gwarantuje, że każdy wątek, który czyta pole, zobaczy ostatnio zapisaną wartość." - Josh Bloch

Jeśli myślisz o użyciu volatile, przeczytaj na opakowaniu java.util.concurrent która zajmuje się atomowym zachowaniem.

Post Wikipedii na Singleton wzór pokazuje Lotne W UŻYCIU.

 185
Author: Ande TURNER,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-17 14:09:42

Ważny punkt o volatile:

  1. synchronizacja w Javie jest możliwa poprzez użycie słów kluczowych Java synchronized i volatile oraz zamków.
  2. w Javie nie możemy mieć zmiennej synchronized. Użycie słowa kluczowego synchronized ze zmienną jest nielegalne i spowoduje błąd kompilacji. Zamiast używać zmiennej synchronized w języku Java, możesz użyć zmiennej java volatile, która poinstruuje wątki JVM, aby odczytały wartość zmiennej volatile z pamięci głównej i nie buforowały jej lokalnie.
  3. jeśli zmienna nie jest współdzielona między wieloma wątkami, nie ma potrzeby używania słowa kluczowego volatile.

Źródło

Przykładowe zastosowanie 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;
    }
}

Tworzymy instancję leniwie w momencie, gdy pojawia się pierwsze żądanie.

Jeśli nie stworzymy zmiennej _instance volatile wtedy wątek, który tworzy instancję Singleton, nie będzie w stanie komunikować się z innym wątkiem. Więc jeśli wątek A tworzy Singleton instancja i zaraz po utworzeniu procesor ulega uszkodzeniu itp., wszystkie inne wątki nie będą w stanie zobaczyć wartości _instance jako not null i uwierzą, że nadal jest przypisana null.

Dlaczego tak się dzieje? Ponieważ wątki reader nie blokują i dopóki wątek writer nie wyjdzie z zsynchronizowanego bloku, pamięć nie zostanie zsynchronizowana, a wartość _instance nie zostanie zaktualizowana w pamięci głównej. Ze słowem kluczowym Volatile w Javie, jest to obsługiwane przez samą Javę i takie aktualizacje będą widoczne dla wszystkich wątków czytnika.

Wniosek: volatile Słowo kluczowe jest również używane do przekazywania zawartości pamięci między wątkami.

Przykładowe użycie bez lotnych:

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;  
    }

Powyższy kod nie jest bezpieczny dla wątków. Chociaż sprawdza wartość instancji ponownie w ramach bloku synchronizowanego (ze względu na wydajność), kompilator JIT może zmienić bajt kodu w taki sposób, że odniesienie do instancji jest ustawiane przed zakończeniem wykonywania przez konstruktora. Oznacza to, że metoda getInstance () zwraca obiekt, który nie został w pełni zainicjowany. Aby zabezpieczyć wątek kodu, od wersji Java 5 można użyć słowa kluczowego volatile dla zmiennej instancji. Zmienne, które są oznaczone jako lotne, są widoczne dla innych wątków dopiero po całkowitym zakończeniu wykonywania przez konstruktora obiektu.
źródło

Tutaj wpisz opis obrazka

volatile zastosowanie w Java :

Iteratory fail-fast są zazwyczaj zaimplementowane przy użyciu licznika volatile na obiekcie list.
  • gdy lista jest aktualizowana, licznik jest zwiększany.
  • kiedy tworzony jest Iterator, bieżąca wartość licznika jest osadzana w obiekcie Iterator.
  • gdy wykonywana jest operacja Iterator, metoda porównuje dwie wartości licznika i rzuca ConcurrentModificationException, jeśli są różne.

Implementacja fail-safe Iteratory są zazwyczaj lekkie. Zazwyczaj opierają się one na właściwościach struktur danych konkretnej implementacji listy. Nie ma ogólnego wzoru.

 142
Author: Premraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 15:45:27

volatile jest bardzo przydatny do zatrzymywania wątków.

Nie to, że powinieneś pisać własne wątki, Java 1.6 ma wiele ładnych puli wątków. Ale jeśli jesteś pewien, że potrzebujesz wątku, musisz wiedzieć, jak go zatrzymać.

Wzór, którego używam dla wątków to:

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
  }
}

W powyższym segmencie kodu wątek odczytujący close W pętli while różni się od tego, który wywołuje close(). Bez volatile, wątek uruchomiony pętli może nigdy nie zobaczyć zmiany do zamknięcia.

Zawiadomienie jak nie ma potrzeby synchronizacji

 59
Author: Pyrolistical,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-11 04:39:08

Jednym z powszechnych przykładów użycia volatile jest użycie zmiennej volatile boolean jako znacznika do zakończenia wątku. Jeśli rozpocząłeś wątek i chcesz mieć możliwość bezpiecznego przerwania go z innego wątku, możesz okresowo sprawdzać flagę wątku. Aby to powstrzymać, Ustaw flagę na true. Wykonując flagę volatile, możesz mieć pewność, że sprawdzający ją wątek zobaczy, że została ustawiona przy następnym sprawdzaniu bez konieczności używania bloku synchronized.

 31
Author: Dave L.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-20 04:00:01

Zmienna zadeklarowana za pomocą słowa kluczowego volatile, ma dwie główne cechy, które czynią ją wyjątkową.

  1. Jeśli mamy zmienną zmienną, nie można jej buforować w pamięci podręcznej komputera(mikroprocesora) przez dowolny wątek. Dostęp zawsze odbywał się z pamięci głównej.

  2. Jeśli istnieje operacja zapisu dzieje się zmienna zmienna, i nagle operacja odczytu jest wymagane, gwarantuje się, że operacja zapisu zostanie zakończona przed operacją odczytu.

Dwie powyższe cechy dedukują, że

  • wszystkie wątki czytające zmienną lotną z pewnością odczytają najnowszą wartość. Ponieważ żadna wartość buforowana nie może jej zanieczyścić. A także żądanie odczytu zostanie udzielone dopiero po zakończeniu bieżącej operacji zapisu.

I z drugiej strony

  • jeśli dalej zbadamy #2 o czym wspomniałem, widzimy, że volatile słowo kluczowe jest idealnym sposobem na utrzymanie współdzielonej zmiennej, która ma 'n' Liczba wątków reader i tylko jeden wątek writer aby uzyskać do niego dostęp. Po dodaniu słowa kluczowego volatile jest to zrobione. Nie ma żadnych innych napowietrznych na temat bezpieczeństwa nici.

We can ' t używać wyłącznie słowa kluczowego volatile, aby zaspokoić współdzieloną zmienną, która ma dostęp do niego ma więcej niż jeden wątek pisarski.

 29
Author: Supun Wijerathne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-05 06:25:40

Tak, zmienna musi być używana, gdy chcesz, aby zmienna była dostępna dla wielu wątków. Nie jest to bardzo powszechne użycie, ponieważ zazwyczaj musisz wykonać więcej niż jedną operację atomową (np. sprawdzić stan zmiennej przed jej modyfikacją), w którym to przypadku zamiast tego użyjesz zsynchronizowanego bloku.

 13
Author: ykaganovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-20 04:26:30

Nikt nie wspomniał o traktowaniu operacji odczytu i zapisu dla typu zmiennej długiej i podwójnej. Odczyty i zapisy są operacjami atomowymi dla zmiennych referencyjnych i dla większości prymitywnych zmiennych, z wyjątkiem długich i podwójnych typów zmiennych, które muszą używać słowa kluczowego volatile, aby być operacjami atomowymi. @ link

 13
Author: Donatello Boccaforno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-11 14:51:29

Moim zdaniem dwa ważne scenariusze poza zatrzymaniem wątku, w którym używane jest słowo kluczowe volatile to:

  1. Podwójnie sprawdzony mechanizm blokujący . Często używane w Singleton design wzór. W tym obiekcie singleton musi być zadeklarowany jako volatile .
  2. Fałszywe Pobudki . Wątek może czasami obudzić się z połączenia oczekującego, nawet jeśli nie zostało wydane żadne powiadomienie. To zachowanie nazywa się fałszywym przebudzeniem. Można temu przeciwdziałać za pomocą warunkowego zmienna (flaga boolean). Umieść wywołanie wait () w pętli while tak długo, jak flaga jest prawdziwa. Więc jeśli wątek obudzi się z połączenia oczekującego z przyczyn innych niż Notify / NotifyAll to napotka flagę jest nadal prawdziwa, a tym samym wywołuje ponownie wait. Przed wywołaniem notify ustaw tę flagę na true. W tym przypadku znacznik boolean jest zadeklarowany jako volatile .
 10
Author: Aniket Thakur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-01 16:45:51

Musisz użyć słowa kluczowego "volatile" lub "synchronized" oraz wszelkich innych narzędzi i technik kontroli współbieżności, które możesz mieć do dyspozycji, jeśli tworzysz wielowątkową aplikację. Przykładem takiej aplikacji są aplikacje desktopowe.

Jeśli tworzysz aplikację, która zostanie wdrożona na serwerze aplikacji (Tomcat, JBoss AS, Glassfish, itp.), nie musisz samodzielnie obsługiwać kontroli współbieżności, ponieważ jest ona już zaadresowana przez serwer aplikacji. W rzeczywistości, jeśli poprawnie zapamiętany standard Java EE zakazuje jakiejkolwiek kontroli współbieżności w servletach i EJB, ponieważ jest częścią warstwy "infrastructure", która powinna być wolna od obsługi. Sterowanie współbieżnością odbywa się w takiej aplikacji tylko wtedy, gdy implementujesz obiekty singleton. To nawet już rozwiązane, jeśli dzianiny swoje komponenty za pomocą frameworkd jak wiosna.

Tak więc w większości przypadków Java development gdzie aplikacja jest aplikacją webową i używa frameworka IOC takiego jak Spring lub EJB, nie musiałbyś używać "lotnych".

 5
Author: Rudi Adianto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-10 18:02:44

volatile tylko gwarantuje, że wszystkie wątki, nawet same, są incrementing. Na przykład: licznik widzi tę samą powierzchnię zmiennej w tym samym czasie. Nie jest używany zamiast zsynchronizowanych lub atomowych lub innych rzeczy, całkowicie sprawia, że odczyty są zsynchronizowane. Nie porównuj go z innymi słowami kluczowymi java. Jak pokazuje poniższy przykład lotne operacje zmiennych są również atomowe, które nie powiodą się lub od razu odniosą sukces.

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);
        }
    }
}

Nawet jeśli umieścisz lotne lub nie Wyniki zawsze będą się różnić. Ale jeśli używasz AtomicInteger jak poniżej wyniki będą zawsze takie same. Tak samo jest z synchronizowane również.

    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
Author: fatih tekin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 15:06:14

Tak, używam go dość często - może być bardzo przydatny dla kodu wielowątkowego. Artykuł, na który wskazałeś, jest dobry. Chociaż są dwie ważne rzeczy, o których należy pamiętać:

  1. Należy używać lotnych tylko wtedy, gdy całkowicie zrozumieć, co to robi i czym się różni synchronizacja. W wielu sytuacjach pojawia się, na powierzchni, aby być prostszym bardziej wykonująca alternatywa dla zsynchronizowane, gdy często lepiej rozumienie lotności uczyniłoby jasne, że synchronized is the only opcja, która by zadziałała.
  2. Lotny nie działa w dużo starszych JVM, chociaż zsynchronizowane. Pamiętam, że widziałem dokument, który odnosił się do różnych poziomów wsparcia w różnych JVMs, ale niestety nie mogę go teraz znaleźć. Zdecydowanie przyjrzyj się temu, jeśli używasz Java pre 1.5 lub jeśli nie masz kontroli nad JVMs, na którym będzie działał Twój program.
 4
Author: MB.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-20 11:07:48

Każdy wątek uzyskujący dostęp do pola lotnego odczytuje jego bieżącą wartość przed kontynuacją, zamiast (potencjalnie) używać wartości buforowanej.

Tylko zmienna składowa może być zmienna lub przejściowa.

 4
Author: tstuber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-11 16:27:12

volatile => synchronized[O firmie]

volatile mówi dla programisty, że wartość zawsze będzie aktualna. Problem polega na tym, że wartość może być zapisana na różnych typach pamięci sprzętowej. Na przykład mogą to być rejestry CPU, Pamięć podręczna CPU, PAMIĘĆ RAM... Rejestry CPU i pamięć podręczna CPU należą do procesora i nie mogą udostępniać danych w przeciwieństwie do pamięci RAM, która jest na ratunek w środowisku wielowątkowym]}

Tutaj wpisz opis obrazka

volatile słowo kluczowe mówi, że zmienna będzie odczyt i zapis Z/do pamięci RAM bezpośrednio . Ma pewne obliczenia footprint

Java 5 extended volatile by supporting happens-before[O firmie]

Zapis do pola zmiennego ma miejsce-przed każdym kolejnym odczytem tego pola.

volatile słowo kluczowe nie leczy sytuacji, w której kilka wątków może zapisać pewne wartości jednocześnie. Odpowiedź brzmi synchronized słowo kluczowe[O firmie]

W rezultacie jest Bezpieczny tylko wtedy, gdy jeden wątekzapisze , a inni po prostu odczytają volatile wartość

 4
Author: yoAlex5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-05 17:21:18

Oczywiście, tak. (I to nie tylko w Javie, ale także w C#.) Są chwile, kiedy musisz uzyskać lub ustawić wartość, która jest gwarantowana jako operacja atomowa na danej platformie, na przykład int lub boolean, ale nie wymagają narzutu blokowania gwintu. Słowo kluczowe volatile pozwala upewnić się, że podczas odczytu wartości otrzymujesz current wartość, a nie wartość buforowaną, która została przestarzała przez zapis w innym wątku.

 3
Author: dgvid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 14:28:48

Istnieją dwa różne zastosowania słowa kluczowego volatile.

  1. uniemożliwia JVM odczytywanie wartości z rejestru (Załóżmy jako cache) i wymusza odczyt jej wartości z pamięci.
  2. zmniejsza ryzyko błędów spójności pamięci.

Uniemożliwia JVM odczyt wartości w rejestrze i wymusza jego wartość odczytywana z pamięci.

A busy flag jest używany, aby zapobiec kontynuowaniu wątku, gdy urządzenie jest zajęte, a flaga nie zabezpieczony zamkiem:

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

Testowanie wątku będzie kontynuowane, gdy inny wątek wyłączy flagę busy :

busy = 0;

Jednakże, ponieważ busy jest często dostępny w wątku testowym, JVM może zoptymalizować test poprzez umieszczenie wartości busy w rejestrze, a następnie przetestować zawartość rejestru bez odczytywania wartości busy w pamięci przed każdym testem. Wątek testowy nigdy nie zobaczy zmiany zajętości, a drugi wątek zmieni tylko wartość zajętości w pamięć, co prowadzi do impasu. Zadeklarowanie znacznika busy jako lotnego wymusza odczytanie jego wartości przed każdym testem.

Zmniejsza ryzyko błędów spójności pamięci.

Używanie zmiennych lotnych zmniejsza ryzyko błędów spójności pamięci , ponieważ każdy zapis do zmiennej lotnej ustanawia "happens-before" relacja z kolejnymi odczytami tej samej zmiennej. Oznacza to, że zmiany zmiennej zmiennej są zawsze widoczne dla innych wątków.

Technika czytania, pisania bez błędów spójności pamięci nazywa się działaniem atomowym.

Akcja atomowa to taka, która skutecznie dzieje się naraz. Akcja atomowa nie może zatrzymać się w środku: albo dzieje się całkowicie, albo wcale. Żadne efekty uboczne działania atomowego nie są widoczne aż do zakończenia działania.

Poniżej znajdują się akcje, które można określić jako atomowe:

  • czyta i pisze są atomowych dla zmiennych referencyjnych i dla większości zmienne prymitywne (wszystkie typy z wyjątkiem long I double).
  • odczyty i zapisy są atomowe dla wszystkich zmiennych zadeklarowanych lotne (w tym zmienne długie i podwójne).
Zdrówko!
 3
Author: Mohanraj Balasubramaniam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-02 08:42:57

Lotny nie podąża za nim.

1 > Odczyt i zapis zmiennych lotnych przez różne wątki są zawsze z pamięci, a nie z własnej pamięci podręcznej lub rejestru procesora wątku. Więc każdy wątek zawsze zajmuje się najnowszą wartością. 2 > Gdy 2 różne wątki pracują z tą samą instancją lub zmiennymi statycznymi w stercie, może się zdarzyć, że inne akcje będą Nie w porządku. Zobacz blog jeremy ' ego Mansona na ten temat. Ale lotność tu pomaga.

Po w pełni uruchomionym kodzie pokazuje jak wiele wątków może wykonać w wstępnie zdefiniowana kolejność i drukowanie wyjść bez użycia zsynchronizowanego słowa kluczowego.

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

Aby to osiągnąć, możemy użyć następującego pełnowartościowego kodu uruchomieniowego.

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
                    }
                }
            }
        }
    }
}

Następujący link github ma readme, który daje właściwe Wyjaśnienie. https://github.com/sankar4git/volatile_thread_ordering

 2
Author: sankar banerjee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-31 06:23:43

Ze strony Oracle documentation pojawia się potrzeba zmiennej zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna zmienna]}

Używanie zmiennych lotnych zmniejsza ryzyko błędów spójności pamięci, ponieważ każdy zapis do zmiennej lotnej ustanawia relację happens-before z kolejnymi odczytami tej samej zmiennej.

Oznacza to, że zmiany w zmiennej volatile są zawsze widoczne dla innych wątków. Oznacza to również, że gdy wątek czyta ulotną zmienna, widzi nie tylko ostatnią zmianę volatile, ale także skutki uboczne kodu, który doprowadził do zmiany.

Jak wyjaśniono w odpowiedzi Peter Parker, w przypadku braku modyfikatora volatile, stos każdego wątku może mieć własną kopię zmiennej. Zmieniając zmienną na volatile, Naprawiono problemy ze spójnością pamięci.

Aby lepiej zrozumieć, zajrzyj na stronę z samouczkiem jenkov.

Spójrz na powiązane pytanie SE, aby uzyskać więcej szczegółów na temat volatile & przypadki użycia lotnych:

Różnica między lotnym a synchronizowanym w Javie

Jeden praktyczny przypadek użycia:

Masz wiele wątków, które muszą wydrukować bieżący czas w określonym formacie, na przykład: java.text.SimpleDateFormat("HH-mm-ss"). Yon może mieć jedną klasę, która zamienia bieżący czas na SimpleDateFormat i aktualizuje zmienną dla każdej sekundy. Wszystkie inne wątki mogą po prostu użyć tej zmiennej do wydruku bieżącego czasu w plikach dziennika.

 1
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:13

Zmienne lotne są synchronizacją wagi lekkiej. Gdy wymagana jest widoczność najnowszych danych wśród wszystkich wątków i może być zagrożona atomiczność , w takich sytuacjach należy preferować zmienne zmienne zmienne. Read on volatile variables zawsze zwraca najnowszy zapis wykonywany przez dowolny wątek, ponieważ nie są one ani buforowane w rejestrach, ani w buforach, w których inne procesory nie widzą. Lotny jest wolny od blokady. Używam volatile, gdy scenariusz spełnia kryteria wymienione powyżej.

 1
Author: Neha Vari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 12:57:06

Chociaż widzę wiele dobrych wyjaśnień teoretycznych w odpowiedziach wymienionych tutaj, dodaję praktyczny przykład z wyjaśnieniem tutaj:

1.

CODE RUN WITHOUT VOLATILE USE

public class VisibilityDemonstration {

private static int sCount = 0;

public static void main(String[] args) {
    new Consumer().start();
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        return;
    }
    new Producer().start();
}

static class Consumer extends Thread {
    @Override
    public void run() {
        int localValue = -1;
        while (true) {
            if (localValue != sCount) {
                System.out.println("Consumer: detected count change " + sCount);
                localValue = sCount;
            }
            if (sCount >= 5) {
                break;
            }
        }
        System.out.println("Consumer: terminating");
    }
}

static class Producer extends Thread {
    @Override
    public void run() {
        while (sCount < 5) {
            int localValue = sCount;
            localValue++;
            System.out.println("Producer: incrementing count to " + localValue);
            sCount = localValue;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                return;
            }
        }
        System.out.println("Producer: terminating");
    }
}
}

W powyższym kodzie są dwa wątki-producent i konsument.

Wątek producenta powtarza się przez pętlę 5 razy (z uśpieniem 1000 milisekund lub 1 sek) pomiędzy. W każdej iteracji wątek producer zwiększa wartość zmiennej sCount o 1. Więc, producent zmienia wartość sCount z 0 do 5 we wszystkich iteracjach

Wątek konsumencki jest w stałej pętli i drukuje za każdym razem, gdy zmienia się wartość sCount, aż wartość osiągnie 5, Gdzie się kończy.

Obie pętle są uruchamiane w tym samym czasie. Tak więc zarówno producent, jak i konsument powinni wydrukować wartość sCount 5 razy.

Wyjście

Consumer: detected count change 0
Producer: incrementing count to 1
Producer: incrementing count to 2
Producer: incrementing count to 3
Producer: incrementing count to 4
Producer: incrementing count to 5
Producer: terminating

Analiza

W powyższym programie, gdy wątek producenta aktualizuje wartość sCount, robi zaktualizuj wartość zmiennej w pamięci głównej(pamięć, z której każdy wątek będzie początkowo odczytywał wartość zmiennej). Ale wątek konsumencki odczytuje wartość sCount tylko za pierwszym razem z tej pamięci głównej, a następnie buforuje wartość tej zmiennej wewnątrz własnej pamięci. Tak więc, nawet jeśli wartość original sCount w pamięci głównej została zaktualizowana przez wątek producenta, wątek konsumencki odczytuje ze swojej buforowanej wartości, która nie jest aktualizowana. To się nazywa widoczność PROBLEM .

2.

CODE RUN WITH VOLATILE USE

W powyższym kodzie zastąp wiersz kodu, w którym sCount jest zadeklarowany przez:

private volatile  static int sCount = 0;

Wyjście

Consumer: detected count change 0
Producer: incrementing count to 1
Consumer: detected count change 1
Producer: incrementing count to 2
Consumer: detected count change 2
Producer: incrementing count to 3
Consumer: detected count change 3
Producer: incrementing count to 4
Consumer: detected count change 4
Producer: incrementing count to 5
Consumer: detected count change 5
Consumer: terminating
Producer: terminating

Analiza

Kiedy zadeklarujemy zmienną volatile, oznacza to, że wszystkie odczyty i wszystkie zapisy do tej zmiennej lub z tej zmiennej trafią bezpośrednio do pamięci głównej. Wartości tych zmiennych nigdy nie będą buforowane.

Jako wartość sCount zmienna nigdy nie jest buforowana przez żaden wątek, konsument zawsze odczytuje oryginalną wartość sCount z pamięci głównej (gdzie jest aktualizowana przez wątek producenta). Tak więc, w tym przypadku wyjście jest poprawne, gdzie oba wątki wyświetlają różne wartości sCount 5 razy.

W ten sposób słowo kluczowe volatile rozwiązuje problem widoczności .

 1
Author: Abhishek Luthra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-05 14:28:25

Załóżmy, że wątek modyfikuje wartość współdzielonej zmiennej, jeśli nie użyłeś modyfikatora volatile dla tej zmiennej. Gdy inne wątki chcą odczytać wartość tej zmiennej, nie widzą zaktualizowanej wartości, ponieważ odczytują wartość zmiennej z pamięci podręcznej procesora zamiast pamięci RAM. Ten problem znany również jako Visibility Problem.

Deklarując współdzieloną zmienną volatile, wszystkie zapisy do zmiennej counter zostaną natychmiast zapisane z powrotem do pamięci głównej. Ponadto wszystkie odczyty licznika zmienna zostanie odczytana bezpośrednio z pamięci głównej.

public class SharedObject {
    public volatile int sharedVariable = 0;
}

W przypadku zmiennych nieulotnych nie ma gwarancji, kiedy Wirtualna Maszyna Java (JVM) odczytuje dane z pamięci głównej do pamięci podręcznej procesora lub zapisuje dane z pamięci podręcznej procesora do pamięci głównej. Może to spowodować kilka problemów, które wyjaśnię w poniższych sekcjach.


Przykład:

Wyobraź sobie sytuację, w której dwa lub więcej wątków ma dostęp do współdzielonego obiektu zawierającego zmienną counter deklarowane tak:

public class SharedObject {
    public int counter = 0;
}

Wyobraź sobie, że tylko Wątek 1 zwiększa zmienną counter, ale zarówno Wątek 1, Jak i wątek 2 mogą odczytywać zmienną counter od czasu do czasu.

Jeśli zmienna counter nie jest zadeklarowana jako zmienna volatile, nie ma gwarancji, kiedy wartość zmiennej counter zostanie zapisana z pamięci podręcznej CPU z powrotem do pamięci głównej. Oznacza to, że wartość zmiennej counter w pamięci podręcznej procesora może nie być taka sama jak w pamięci głównej. Sytuacja ta jest zilustrowana tutaj:

lotne

Problem z wątkami, które nie widzą ostatniej wartości zmiennej, ponieważ nie została jeszcze zapisana z powrotem do pamięci głównej przez inny wątek, nazywany jest problemem "widoczności". Aktualizacje jednego wątku nie są widoczne dla innych wątków.

 1
Author: Amin Soheyli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-03 13:21:58

Zmienna Volatile jest w zasadzie używana do natychmiastowej aktualizacji (flush) w głównej linii współdzielonej pamięci podręcznej po jej zaktualizowaniu, tak aby zmiany natychmiast odzwierciedlały wszystkie wątki robocze.

 0
Author: Niyaz Ahamad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-17 11:00:18

Klucz Lotny, gdy jest używany ze zmienną, upewni się, że wątki czytające tę zmienną będą widzieć tę samą wartość . Teraz, jeśli masz wiele wątków odczytu i zapisu do zmiennej, co zmienna zmienna nie wystarczy i dane zostaną uszkodzone . Wątki graficzne odczytały tę samą wartość, ale każdy z nich wykonał kilka czatów (np. zwiększony licznik), przy zapisie z powrotem do pamięci naruszana jest integralność danych . Dlatego konieczne jest, aby zmienny synchronized (different ways are possible)

Jeśli zmiany są wykonywane przez 1 wątek, a pozostałe muszą tylko odczytać tę wartość, zmienna będzie odpowiednia.

 -1
Author: Java Main,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-24 16:41:21

Poniżej znajduje się bardzo prosty kod, aby zademonstrować Wymaganie volatile dla zmiennej, która jest używana do kontrolowania wykonania wątku z innego wątku (jest to jeden scenariusz, w którym volatile jest wymagane).

// 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());
    }
}

Gdy volatile nie jest używane:nigdy nie zobaczysz komunikatu " Stopped on: xxx", nawet po " stopped on: xxx", a program nadal działa.

Stopping on: 1895303906650500

Kiedy volatile używane: zobaczysz ' zatrzymane na: xxx ' natychmiast.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Demo: https://repl.it/repls/SilverAgonizingObjectcode

 -2
Author: manikanta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-04 05:34:46