72 votes

Exemple le plus simple et compréhensible de mot clé volatile en java

Je suis en train de lire à propos de mot-clé volatile en Java et de bien comprendre la théorie de la partie.

Mais, ce que je cherche, c'est un bon exemple de cas, ce qui montre qu'arriverait-il si la variable n'est pas volatile et si c'était le cas.

Ci-dessous un extrait de code qui ne fonctionne pas comme prévu ( à partir de aioobe)

class Test extends Thread {

    boolean keepRunning = true;

    public void run() {
        while (keepRunning) {
        }

        System.out.println("Thread terminated.");
    }

    public static void main(String[] args) throws InterruptedException {
        Test t = new Test();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning set to false.");
    }
}

Idéalement, si keepRunning n'est pas volatile, fil devrait continuer à courir indefinetely. Mais, il n'arrête après quelques secondes.

J'ai deux question :-

  • Quelqu'un peut-il expliquer la volatilité exemple ? Pas avec la théorie de JLS.
  • Est volatile substitut pour la synchronisation ? N'a-t-il atteindre l'atomicité ?

48voto

Narendra Pathai Points 12172

Volatile --> Garantit la visibilité et de ne PAS l'atomicité

Synchronisation (Verrouillage) --> Garantit la visibilité et l'atomicité (si c'est fait correctement)

Volatile n'est pas un substitut pour la synchronisation

Utilisation volatile que lorsque vous êtes à la mise à jour de la référence et de ne pas faire certaines autres opérations sur elle.

Exemple:

volatile int i = 0;

public void incrementI(){
   i++;
}

ne sera pas thread-safe, sans l'utilisation de la synchronisation ou AtomicInteger que l'incrémentation est un composé de l'opération.

Pourquoi ne pas s'exécuter indéfiniment?

En fait ça dépend de plusieurs circonstances. Dans la plupart des cas, la JVM est assez intelligent pour vider le contenu.

L'utilisation correcte de la volatilité traite des différentes utilisations possibles de la volatilité. À l'aide de volatiles correctement est difficile, je dirais que "dans le doute, abstenez", l'utilisation synchronisée bloc à la place.

Aussi:

synchronisé bloc peut être utilisé à la place de la volatilité, mais l'inverse n'est pas vrai.

27voto

user882209 Points 415

Pour votre exemple: si pas déclaré volatiles de la JVM de serveur pourrait hisser keepRunning variable en dehors de la boucle, car il n'est pas modifiée dans la boucle (en le transformant en une boucle infinie), mais le client JVM ne le serait pas. C'est pourquoi vous voyez des résultats différents.

Explication générale sur les variables suivantes:

Lorsqu'un champ est déclarée volatile, le compilateur et l'exécution sont avisés que cette variable est partagée et que les opérations sur il ne devrait pas être réorganisée avec d'autres opérations de mémoire. Variables ne sont pas mis en cache dans les registres ou dans les caches où ils sont cachés provenant d'autres processeurs, et une lecture d'une variable volatile renvoie toujours la plus récente écrire par n'importe quel thread.

La visibilité des effets de la volatilité des variables de prolonger au-delà de la valeur de la volatilité de la variable elle-même. Lorsque le thread d'Un écrit à un volatile variable et par la suite le fil B lit la même variable, les valeurs de toutes les variables qui étaient visibles à Un avant d'écrire à la volatilité des variables deviennent visibles à B après la lecture de la volatilité de la variable

L'utilisation la plus courante de la volatilité des variables est comme un accomplissement, de l'interruption ou de l'indicateur d'état:

  volatile boolean flag;
  while (!flag)  {
     // do something untill flag is true
  }

Variables peuvent être utilisées pour d'autres types d'informations d'état, mais plus d'attention est requise lors de la tentative de cette. Par exemple, la sémantique de la volatilité ne sont pas assez fort pour faire de l'opération d'incrémentation (count++) atomique, sauf si vous pouvez garantir que la variable est écrite qu'à partir d'un seul fil.

Le verrouillage peut garantir à la fois la visibilité et l'atomicité; variables ne peuvent garantir la visibilité.

Vous pouvez utiliser des variables volatiles que lorsque tous les critères suivants sont respectés:

  • Écrit à la variable ne dépend pas de sa valeur actuelle, ou vous pouvez s'assurer qu'un seul thread jamais les mises à jour de la valeur;
  • La variable ne doit pas participer à des invariants avec d'autres variables d'état; et
  • Le verrouillage n'est pas nécessaire pour toute autre raison, alors que la variable est en cours d'accès.

Débogage astuce: assurez-vous de toujours spécifier le serveur de la JVM commutateur de ligne de commande lors de l'appel de la JVM, même pour le développement et les tests. La JVM de serveur effectue plus de l'optimisation de la JVM client, tels que le levage des variables en dehors d'une boucle qui ne sont pas modifiés dans la boucle; code qui peut apparaître à travailler dans l'environnement de développement (client JVM) peuvent se casser dans l'environnement de déploiement (JVM de serveur).

Ceci est un extrait de Java de la Simultanéité dans la Pratique, le meilleur livre que vous pouvez trouver sur ce sujet.

14voto

paritosht Points 9

J'ai légèrement modifié votre exemple. Utilisez maintenant l'exemple avec keepRunning en tant que membre volatile et non volatile:

 public class TestVolatile extends Thread{
 boolean keepRunning = true;

    public void run() {
        long count=0;
        while (keepRunning) {
            count++;
        }

        System.out.println("Thread terminated."+count);
    }

    public static void main(String[] args) throws InterruptedException {
        TestVolatile t = new TestVolatile();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning set to false.");
    }
}
 

6voto

Gray Points 58585

Idéalement, si keepRunning n'est pas volatile, fil devrait continuer à courir indéfiniment. Mais, il n'arrête après quelques secondes.

Si vous exécutez dans un seul processeur ou si votre système est très occupé, le système d'exploitation peut être de changer les fils qui provoque des niveaux d'invalidation du cache. Comme d'autres l'ont mentionné, de ne pas avoir un volatile ne signifie pas que la mémoire va pas être partagée, mais la JVM est d'essayer de ne pas synchroniser la mémoire si elle peut pour des raisons de performances.

Un autre pense à noter est que l' System.out.println(...) est synchronisé parce que le sous-jacent PrintStream t de la synchronisation de l'arrêt de chevauchement de sortie. Si vous êtes l'obtention de la mémoire de la synchronisation "gratuitement" dans le thread. Cela n'explique toujours pas pourquoi la lecture de la boucle voit les mises à jour à tous cependant.

Si l' println(...) des lignes sont dans ou à l'extérieur, votre programme tourne pour moi sous Java6 sur un MacBook Pro avec un processeur Intel core i7.

Quelqu'un peut-il expliquer la volatilité exemple ? Pas avec la théorie de JLS.

Je pense que votre exemple est bon. Je ne sais pas pourquoi il ne fonctionne pas avec tous System.out.println(...) états supprimé. Il fonctionne pour moi.

Est volatile substitut pour la synchronisation ? N'a-t-il atteindre l'atomicité ?

En termes de mémoire de synchronisation, volatile jette même les barrières de la mémoire en tant que synchronized bloc sauf que l' volatile barrière est uni-directionnel rapport bi-directionnelle. volatile lit jetez une charge de la barrière de tout écrit jeter un magasin de la barrière. Un synchronized bloc est un bi-directionnelle de la barrière.

En termes de atomicity, cependant, la réponse est "ça dépend". Si vous êtes à la lecture ou l'écriture d'une valeur dans un champ, alors volatile permet une atomicité. Cependant, l'incrémentation d'un volatile champ souffre de la limitation ++ est en fait 3 opérations: lecture, l'accroissement, l'écriture. Dans ce cas, ou plus complexes, mutex cas, une synchronized bloc est dans l'ordre.

3voto

Jeff Storey Points 22103

Lorsqu'une variable est - volatile, c'est la garantie qu'il ne sera pas mis en cache et que les différents threads de voir la mise à jour de la valeur. Cependant, pas de marquage, il volatile ne garantit pas la oppostie. volatile a été l'une des choses qui a été brisé dans la JVM pour un temps long et pas toujours bien compris (et souvent laissé de côté par les développeurs). Si la JVM est assez intelligent pour ne pas mettre en cache les valeurs de la variable indéfiniment, si vous devez marquer volatile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X