Point important sur volatile
:
- La synchronisation en Java est possible en utilisant des mots - clés Java
synchronized
et volatile
et serrures.
- En Java, nous ne pouvons pas avoir de
synchronized
variable. L'utilisation d'un synchronized
mot clé avec une variable est illégale et entraînera une erreur de compilation. Au lieu d'utiliser la synchronized
variable en Java, vous pouvez utiliser la volatile
variable java , qui demandera aux threads JVM de lire la valeur de la volatile
variable dans la mémoire principale et de ne pas la mettre en cache localement.
- Si une variable n'est pas partagée entre plusieurs threads, il n'est pas nécessaire d'utiliser le
volatile
mot clé.
la 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 une instance paresseusement au moment de la première demande.
Si nous ne faisons pas la _instance
variable, volatile
le thread qui crée l'instance de Singleton
n'est pas en mesure de communiquer avec l'autre thread. Donc, si le thread A crée une instance Singleton et juste après sa création, le CPU corrompt, etc., tous les autres threads ne pourront pas voir la valeur de _instance
comme non nul et ils croiront qu'il est toujours attribué null.
Pourquoi cela arrive-t-il? Étant donné que les threads de lecture ne font aucun verrouillage et tant que le thread d'écriture ne sort pas d'un bloc synchronisé, la mémoire ne sera pas synchronisée et la valeur de _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 de lecture.
Conclusion : le volatile
mot-clé est également utilisé pour communiquer le contenu de la mémoire entre les threads.
Exemple d'utilisation de sans volatile:
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 ait terminé son exécution. Cela signifie que la méthode getInstance () renvoie un objet qui n'a peut-être pas été complètement initialisé. 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 volatiles ne sont visibles que pour les autres threads une fois que le constructeur de l'objet a complètement terminé son exécution.
La source
volatile
utilisation en Java :
Les itérateurs à échec rapide sont généralement implémentés à l'aide d'un volatile
compteur sur l'objet 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' Iterator
objet.
- Lorsqu'une
Iterator
opération est effectuée, la méthode compare les deux valeurs de compteur et renvoie a ConcurrentModificationException
si elles sont différentes.
L'implémentation d'itérateurs à sécurité intégrée 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 schéma général.
volatile
celle fournie avec le nouveau modèle de mémoire Java défini dans JSR 133: que lorsqu'un thread lit unevolatile
variable, il voit non seulement la dernière valeur qui lui a été écrite par un autre thread, mais aussi toutes les autres écritures sur d'autres variables qui étaient visibles dans cet autre fil au moment de l'volatile
écriture. Voir cette réponse et cette référence .