Question

Au travail aujourd'hui, je suis tombé sur le mot clé volatile en Java. Ne le connaissant pas très bien, j'ai trouvé cette explication:

  

Théorie et pratique de Java: gestion de la volatilité

Etant donné le détail dans lequel cet article explique le mot clé en question, l'utilisez-vous déjà ou pouvez-vous jamais voir un cas dans lequel vous pourriez utiliser ce mot clé de manière correcte?

Était-ce utile?

La solution

volatile a une sémantique pour la visibilité de la mémoire. Fondamentalement, la valeur d'un champ volatile devient visible pour tous les lecteurs (notamment les threads) après qu'une opération d'écriture soit terminée. Sans volatile , les lecteurs pourraient voir une valeur non mise à jour.

Pour répondre à votre question: Oui, j'utilise une variable volatile pour contrôler si du code continue une boucle. La boucle teste la valeur volatile et continue si elle est true . La condition peut être définie sur false en appelant un " arrêt " méthode. La boucle voit false et se termine lorsqu'elle teste la valeur après l'exécution de la méthode d'arrêt.

Le livre " La concurrence de Java dans la pratique , " que je recommande fortement, donne une bonne explication de volatile . Ce livre est écrit par la même personne que celle qui a écrit l'article d'IBM auquel il est fait référence dans la question (en fait, il cite son livre au bas de cet article). Mon utilisation de volatile correspond à ce que son article appelle l'indicateur d'état "modèle 1".

Si vous souhaitez en savoir plus sur la manière dont volatile fonctionne sous le capot, consultez la section le modèle de mémoire Java . Si vous voulez aller au-delà de ce niveau, consultez un bon livre d’architecture comme Hennessy & amp; Patterson et découvrez la cohérence et la cohérence du cache.

Autres conseils

& # 8220; & # 8230; le modificateur volatile garantit que tout thread qui lit un champ verra la dernière valeur écrite. & <8221; - Josh Bloch

Si vous envisagez d'utiliser volatile , consultez le package java.util.concurrent qui traite du comportement atomique.

Le message de Wikipedia sur un Singleton Pattern est utilisé de manière volatile.

Point important sur volatile :

  1. La synchronisation en Java est possible à l’aide des mots-clés Java synchronisés , volatile et des verrous.
  2. En Java, nous ne pouvons pas avoir de variable synchronized . L'utilisation du mot clé synchronized avec une variable est illégale et entraînera une erreur de compilation. Au lieu d'utiliser la variable synchronized en Java, vous pouvez utiliser la variable java volatile , qui donnera pour instruction aux threads JVM de lire la valeur de la variable volatile . dans la mémoire principale et ne le cachez pas localement.
  3. Si une variable n'est pas partagée entre plusieurs threads, il n'est pas nécessaire d'utiliser le mot clé volatile .

source

Exemple d'utilisation de 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;
    }
}

Nous créons instance paresseusement au moment de la première demande.

Si nous ne rendons pas la variable _instance volatile , le thread qui crée l'instance de Singleton ne peut pas communiquer avec le autre fil. Donc, si le thread A crée l'instance Singleton et juste après la création, le processeur corrompt, etc., tous les autres threads ne pourront pas voir la valeur de _instance comme non nulle et ils croiront qu'elle est toujours affectée à null .

Pourquoi cela se produit-il? Etant donné que les threads de lecteur ne font pas de verrouillage et tant que le thread d’écriture n’est pas sorti d’un bloc synchronisé, la mémoire ne sera pas synchronisée et la valeur _instance ne sera pas mise à jour dans la mémoire principale. Avec le mot clé Volatile en Java, cela est géré par Java lui-même et ces mises à jour seront visibles par tous les threads du lecteur.

  

Conclusion : le mot clé volatile est également utilisé pour communiquer le contenu de la mémoire entre les threads.

Exemple d'utilisation de sans 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;  
    }

Le code ci-dessus n'est pas thread-safe. Bien qu'il vérifie à nouveau la valeur de l'instance dans le bloc synchronisé (pour des raisons de performances), le compilateur JIT peut réorganiser le bytecode de manière à ce que la référence à l'instance soit définie avant que le constructeur n'ait terminé son exécution. Cela signifie que la méthode getInstance () renvoie un objet qui n'a peut-être pas été initialisé complètement. Pour rendre le code thread-safe, le mot-clé volatile peut être utilisé depuis Java 5 pour la variable d'instance. Les variables marquées comme étant volatiles ne sont visibles par les autres threads que lorsque le constructeur de l'objet a terminé son exécution.
Source

 entrez la description de l'image ici

utilisation volatile en Java :

Les itérateurs de type fast-fast sont généralement mis en œuvre à l'aide d'un compteur volatile sur l'objet de liste.

  • Lorsque la liste est mise à jour, le compteur est incrémenté.
  • Lorsqu'un Iterator est créé, la valeur actuelle du compteur est incorporée dans l'objet Iterator .
  • Lorsqu'une opération Iterator est effectuée, la méthode compare les deux valeurs de compteur et lève une ConcurrentModificationException si elles sont différentes.

L'implémentation d'itérateurs à sécurité intrinsèque est généralement légère. Ils s'appuient généralement sur les propriétés des structures de données de l'implémentation de liste spécifique. Il n'y a pas de tendance générale.

volatile est très utile pour arrêter les threads.

Non pas que vous deviez écrire vos propres threads, Java 1.6 possède de nombreux pools de threads agréables. Mais si vous êtes sûr d'avoir besoin d'un fil, vous devez savoir comment l'arrêter.

Le modèle que j'utilise pour les discussions est le suivant:

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

Remarquez que la synchronisation n'est pas nécessaire

Un exemple courant d'utilisation de volatile consiste à utiliser une variable volatile boolean en tant qu'indicateur pour terminer un thread. Si vous avez démarré un thread et que vous souhaitez pouvoir l'interrompre en toute sécurité depuis un autre thread, vous pouvez le faire vérifier régulièrement un indicateur. Pour l'arrêter, définissez l'indicateur sur true. En rendant l'indicateur volatile , vous pouvez vous assurer que le thread qui le vérifie verra qu'il a été défini lors de sa prochaine vérification sans avoir même à utiliser un bloc synchronisé . .

Une variable déclarée avec le mot clé volatile a deux qualités principales qui la rendent spéciale.

  1. Si nous avons une variable volatile, elle ne peut pas être mise en cache dans la mémoire cache de l'ordinateur (microprocesseur) par aucun thread. L’accès a toujours eu lieu à partir de la mémoire principale.

  2. S'il existe une opération d'écriture sur une variable volatile, et tout à coup une opération de lecture est demandé, il est garanti que l'opération d'écriture sera terminée avant l'opération de lecture .

Deux qualités ci-dessus en déduisent que

  • Tous les threads qui lisent une variable volatile liront définitivement la dernière valeur. Parce qu'aucune valeur en cache ne peut la polluer. De plus, la demande de lecture ne sera accordée qu'après l'achèvement de l'opération d'écriture en cours.

Et d'autre part,

  • Si nous étudions plus avant le # 2 que j'ai mentionné, nous pouvons constater que le mot clé volatile est un moyen idéal de conserver une variable partagée contenant < em> 'n' nombre de threads lus et un seul thread d'écriture pour y accéder. Une fois que nous avons ajouté le mot clé volatile , c'est terminé. Aucune autre surcharge sur la sécurité des threads.

Inversement,

Nous ne pouvons pas utiliser le mot clé volatile uniquement pour satisfaire une variable partagée qui a plus de on écrit des discussions y accédant .

Oui, volatile doit être utilisé chaque fois que vous souhaitez qu'une variable mutable soit accessible par plusieurs threads. Ce n'est pas très courant car nous avons généralement besoin de plus d'une opération atomique (par exemple, vérifier l'état de la variable avant de la modifier), auquel cas vous utiliseriez plutôt un bloc synchronisé.

Personne n’a mentionné le traitement des opérations de lecture et d’écriture pour les types longue et double variable. Les lectures et les écritures sont des opérations atomiques pour les variables de référence et pour la plupart des variables primitives, à l'exception des types de variables longues et doubles, qui doivent utiliser le mot clé volatile pour être des opérations atomiques. @link

À mon avis, deux scénarios importants autres que l'arrêt du fil dans lequel le mot clé volatile est utilisé sont les suivants:

  1. Mécanisme de verrouillage revérifié . Utilisé souvent dans la conception Singleton modèle. Dans ce cas, l'objet singleton doit être déclaré volatil .
  2. Wakeups parasites . Un fil peut parfois sortir de l'appel en attente même si aucun appel de notification n'a été émis. Ce comportement s'appelle le réveil suprême. Ceci peut être contré en utilisant une variable conditionnelle (indicateur booléen). Placez l'appel wait () dans une boucle while tant que le drapeau est vrai. Donc, si le thread sort d'un appel en attente pour une raison autre que notify / notifyall, alors le drapeau de rencontre est toujours vrai et les appels attendent donc à nouveau. Avant d'appeler notify, définissez cet indicateur sur true. Dans ce cas, le drapeau booléen est déclaré volatil .

Vous devrez utiliser un mot clé "volatile" ou "synchronisé", ainsi que tous les autres outils et techniques de contrôle de la simultanéité à votre disposition si vous développez une application multithread. Les applications de bureau constituent un exemple de cette application.

Si vous développez une application qui serait déployée sur un serveur d'applications (Tomcat, JBoss AS, Glassfish, etc.), vous n'avez pas à gérer vous-même le contrôle de la simultanéité, car il est déjà adressé par le serveur d'applications. En fait, si je me souvenais bien, la norme Java EE interdisait tout contrôle de la simultanéité dans les servlets et les EJB, car il fait partie de la couche «infrastructure» dont vous êtes censé être libéré. Vous ne contrôlez la concurrence que dans une telle application si vous implémentez des objets singleton. Ce problème est déjà résolu si vous composez vos composants avec frameworkd, comme Spring.

Ainsi, dans la plupart des cas de développement Java où l'application est une application Web et utilisant un framework IoC tel que Spring ou EJB, vous n'avez pas besoin d'utiliser 'volatile'.

volatile garantit uniquement que tous les threads, même eux-mêmes, sont incrémentés. Par exemple: un compteur voit le même visage de la variable en même temps. Il n'est pas utilisé à la place de choses synchronisées, atomiques ou autres, il rend complètement les lectures synchronisées. Veuillez ne pas le comparer avec d'autres mots-clés java. Comme le montre l'exemple ci-dessous, les opérations sur les variables volatiles sont également atomiques: elles échouent ou réussissent d'un coup.

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

Même si vous mettez des résultats instables ou non, les résultats seront toujours différents. Mais si vous utilisez AtomicInteger comme ci-dessous, les résultats seront toujours les mêmes. C'est pareil avec synchronisé également.

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

Oui, je l’utilise beaucoup - cela peut être très utile pour du code multithread. L'article que vous avez mentionné est bon. Bien qu'il y ait deux choses importantes à garder à l'esprit:

  1. Vous ne devez utiliser volatile que si vous comprendre tout à fait ce qu'il fait et comment cela diffère de synchronisé. Dans de nombreuses situations, l’instabilité apparaît, en surface, pour être un simple plus alternative performante à synchronisé, quand souvent un meilleur compréhension de volatile rendrait clair que synchronisé est le seul option qui fonctionnerait.
  2. volatile ne fonctionne pas réellement dans un beaucoup de JVM plus anciennes, bien que synchronisé fait. Je me souviens d’avoir vu un document faisant référence aux différents niveaux de prise en charge dans différentes machines virtuelles, mais malheureusement, je ne le trouve pas pour le moment. Examinez-le à fond si vous utilisez Java pre 1.5 ou si vous n’avez pas le contrôle sur les machines virtuelles sur lesquelles votre programme sera exécuté.

Absolument, oui. (Et pas seulement en Java, mais aussi en C #.) Il est parfois nécessaire d’obtenir ou de définir une valeur qui est garantie comme une opération atomique sur votre plate-forme donnée, un int ou un booléen, par exemple, mais n’exige pas les frais généraux de blocage de fil. Le mot clé volatile vous permet de vous assurer que lorsque vous lisez la valeur, vous obtenez la valeur actuelle et non une valeur en cache qui vient d'être rendue obsolète par une écriture sur un autre thread.

Chaque thread qui accède à un champ volatile lit sa valeur actuelle avant de continuer, au lieu d'utiliser (potentiellement) une valeur en cache.

Seule la variable membre peut être volatile ou transitoire.

Il existe deux utilisations différentes du mot clé volatile.

  1. Empêche JVM de lire les valeurs du registre (en tant que cache) et force la lecture de sa valeur dans la mémoire.
  2. Réduit le risque d'erreurs de cohérence de la mémoire.
  

Empêche JVM de lire les valeurs dans le registre et force sa   valeur à lire de la mémoire.

Un indicateur occupé est utilisé pour empêcher un thread de continuer pendant que le périphérique est occupé et que l'indicateur n'est pas protégé par un verrou:

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

Le thread de test continue lorsqu'un autre thread désactive l'indicateur occupé :

busy = 0;

Cependant, étant donné que Occupé est fréquemment utilisé dans le processus de test, la machine virtuelle Java peut optimiser le test en plaçant la valeur occupé du registre dans un registre, puis tester le contenu du registre sans lire la valeur occupé en mémoire avant chaque test. Le thread de test ne verrait jamais occupé occupé et l'autre thread ne modifierait que la valeur occupé en mémoire, entraînant un blocage. Déclarer le drapeau occupé comme volatile force la lecture de sa valeur avant chaque test.

  

Réduit le risque d'erreur de cohérence de la mémoire.

L'utilisation de variables volatiles réduit le risque d'erreur de cohérence de la mémoire , car toute écriture dans une variable volatile établit une La relation se produit-avant <& em> avec les lectures ultérieures de cette même variable. Cela signifie que les modifications apportées à une variable volatile sont toujours visibles par les autres threads.

La technique de lecture, écriture sans erreurs de cohérence de mémoire est appelée action atomique .

Une action atomique est une action qui se produit effectivement en même temps. Une action atomique ne peut pas s’arrêter au milieu: elle se produit complètement ou ne se produit pas du tout. Aucun effet secondaire d'une action atomique n'est visible jusqu'à ce que l'action soit terminée.

Vous trouverez ci-dessous des actions que vous pouvez spécifier comme étant atomiques:

  • Les lectures et écritures sont atomiques pour les variables de référence et pour la plupart Variables primitives (tous types sauf long et double).
  • Les lectures et les écritures sont atomiques pour toutes les variables déclarées volatiles . (y compris les variables longues et doubles).

Salut!

Les variables volatiles sont une synchronisation légère. Lorsque la visibilité des dernières données parmi tous les threads est requise et que l'atomicité peut être compromise, dans de telles situations, les variables volatiles doivent être préférées. Les variables de lecture sur volatiles renvoient toujours les écritures les plus récentes effectuées par un thread, car elles ne sont ni mises en cache dans des registres ni dans des caches où les autres processeurs ne peuvent pas voir. Volatile est Lock-Free. J'utilise volatile, lorsque le scénario répond aux critères mentionnés ci-dessus.

Volatile ne suit.

1 > La lecture et l'écriture de variables volatiles par différents threads proviennent toujours de la mémoire, et non du propre cache ou du registre du processeur du thread. Ainsi, chaque fil traite toujours avec la dernière valeur. 2 > Lorsque 2 threads différents fonctionnent avec la même instance ou avec des variables statiques identiques, on peut voir les actions des autres comme étant en panne. Voir le blog de jeremy manson à ce sujet. Mais volatile aide ici.

Le code complet suivant montre comment un certain nombre de threads peuvent s'exécuter dans un ordre prédéfini et imprimer des sorties sans utiliser de mot clé synchronisé.

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

Pour ce faire, nous pouvons utiliser le code courant complet suivant.

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

Le lien github suivant a un fichier Lisez-moi, qui donne une explication appropriée. https://github.com/sankar4git/volatile_thread_ordering

D'après la documentation d'Oracle, page , le besoin de mémoire volatile Une variable permet de résoudre les problèmes de cohérence de la mémoire:

  

L'utilisation de variables volatiles réduit le risque d'erreur de cohérence de la mémoire, car toute écriture dans une variable volatile établit une relation passe-avant avec les lectures suivantes de cette même variable.

Cela signifie que les modifications apportées à une variable volatile sont toujours visibles par les autres threads. Cela signifie également que lorsqu'un thread lit une variable volatile, il voit non seulement la dernière modification apportée à volatile , mais également les effets secondaires du code qui a provoqué la modification.

Comme expliqué dans la réponse de Peter Parker , en l'absence de modificateur volatile , la pile de chaque thread peut avoir sa propre copie de variable. En rendant la variable volatile , les problèmes de cohérence de la mémoire ont été corrigés.

Consultez la page du tutoriel jenkov pour une meilleure compréhension.

Consultez la question SE sur le sujet pour plus de détails sur volatile & amp; cas d'utilisation pour utiliser volatile:

Différence entre volatile et synchronisé en Java

Un cas d'utilisation pratique:

Vous avez de nombreux threads qui doivent imprimer l'heure actuelle dans un format particulier, par exemple: java.text.SimpleDateFormat ("HH-mm-ss") . Yon peut avoir une classe, qui convertit l'heure actuelle en SimpleDateFormat et met à jour la variable toutes les secondes. Tous les autres threads peuvent simplement utiliser cette variable volatile pour imprimer l'heure actuelle dans les fichiers journaux.

Une variable volatile est modifiée de manière asynchrone par l'exécution simultanée de threads dans une application Java. Il n’est pas autorisé d’avoir une copie locale d’une variable différente de la valeur actuellement détenue dans le champ "principal". Mémoire. En effet, une donnée déclarée volatile doit avoir ses données synchronisées sur tous les threads, de sorte que chaque fois que vous accédez à la variable ou que vous la mettez à jour dans un thread, tous les autres threads voient immédiatement la même valeur. Bien entendu, il est probable que les variables volatiles ont un accès et des frais de mise à jour plus importants que les variables "simples". variables, car les threads de raison peuvent avoir leur propre copie de données pour une meilleure efficacité.

Lorsqu'un champ est déclaré volatil, le compilateur et le moteur d'exécution sont avertis que cette variable est partagée et que ses opérations ne doivent pas être réorganisées avec d'autres opérations en mémoire. Les variables volatiles ne sont pas mises en cache dans les registres ni dans les caches où elles se trouvent. masqué par les autres processeurs, la lecture d'une variable volatile renvoie toujours l'écriture la plus récente par un thread.

Pour référence, reportez-vous à ce http: // techno -terminal.blogspot.fr 2015/11/what-are-volatile-variables.html

La clé volatile, lorsqu'elle est utilisée avec une variable, s'assurera que les threads lisant cette variable verront la même valeur. Maintenant, si vous avez plusieurs threads en lecture et en écriture sur une variable, rendre la variable volatile ne sera pas suffisant et les données seront corrompues. Les threads d'image ont lu la même valeur, mais chacun d'entre eux a fait quelques sauts (disons incrémenté d'un compteur). Lors de l'écriture dans la mémoire, l'intégrité des données est violée. C’est pourquoi il est nécessaire de synchroniser la varible (différentes manières sont possibles)

Si les modifications sont effectuées par 1 thread et que les autres n'ont besoin que de lire cette valeur, le volatile sera approprié.

J'aime les l'explication de Jenkov :

  

Le mot clé Java volatile permet de marquer une variable Java comme étant "en cours de stockage dans la mémoire principale". Plus précisément, cela signifie que chaque lecture d'une variable volatile sera lue dans la mémoire principale de l'ordinateur, et non dans le cache du processeur, et que toute écriture dans une variable volatile sera écrite dans la mémoire principale, et pas uniquement dans le cache du processeur. .

     

En fait, depuis Java 5, le mot-clé volatile garantit plus que cela.   Les variables volatiles sont écrites et lues dans la mémoire principale.

C’est une garantie de visibilité étendue appelée garantie sur la survenue d’avant-match.

  

Considérations sur les performances des composants volatiles

     

La lecture et l'écriture de variables volatiles entraînent la lecture ou l'écriture de la variable dans la mémoire principale. La lecture et l'écriture dans la mémoire principale sont plus coûteuses que l'accès au cache du processeur. L'accès aux variables volatiles empêche également la réorganisation des instructions, technique d'amélioration des performances normale. Ainsi, vous ne devriez utiliser des variables volatiles que lorsque vous avez vraiment besoin de renforcer la visibilité des variables.

La variable volatile est généralement utilisée pour la mise à jour instantanée (vidage) de la ligne principale du cache partagé une fois mise à jour, afin que les modifications soient immédiatement répercutées sur tous les threads de travail.

Ci-dessous, un code très simple pour démontrer la nécessité de volatile pour la variable utilisée pour contrôler l'exécution du thread à partir d'un autre thread (il s'agit d'un scénario dans lequel volatile est obligatoire).

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

Lorsque volatile n'est pas utilisé: , vous ne verrez jamais le message ' Arrêté le: xxx ' même après le message ' Arrêter le : xxx 'et le programme continue à s'exécuter.

Stopping on: 1895303906650500

En cas d'utilisation de volatile : , le ' arrêté sur: xxx ' s'affiche immédiatement.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Démo: https://repl.it/repls/SilverAgonizingObjectcode

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top