Est-ce qu’un volatil int dans Java thread-safe?

Est-ce qu’un volatil int dans Java thread-safe? Autrement dit, peut-il être lu et écrit en toute sécurité sans être verrouillé?

Oui, vous pouvez y lire et y écrire en toute sécurité, mais vous ne pouvez rien faire de nouveau, comme l’incrémenter en toute sécurité, car c’est un cycle de lecture / modification / écriture. Il y a aussi la question de son interaction avec l’access à d’ autres variables.

La nature précise de volatile est franchement déroutante (voir la section modèle de mémoire du JLS pour plus de détails ) – AtomicInteger , AtomicInteger plutôt AtomicInteger , comme moyen plus simple de m’assurer que tout se passe bien.

[…] comme être capable de lire et d’écrire en toute sécurité sans verrouiller?

Oui, une lecture entraînera toujours la valeur de la dernière écriture (et les deux lectures et écritures sont des opérations atomiques).

Une lecture / écriture volatile introduit une relation dite de passe-avant dans l’exécution.

À partir de la spécification du langage Java Chapitre 17: Threads et verrous

Une écriture dans un champ volatile (§8.3.1.4) se produit avant chaque lecture ultérieure de ce champ.

En d’autres termes, lorsque vous traitez des variables volatiles, vous n’avez pas besoin de synchroniser explicitement (introduire une relation «passe avant») en utilisant synchronized mot clé synchronized pour vous assurer que le thread obtient la dernière valeur écrite dans la variable.

Comme Jon Skeet le souligne, l’utilisation de variables volatiles est limitée, et vous devriez en général envisager d’utiliser des classes du package java.util.concurrent .

L’access à volatile int en Java sera sécurisé pour les threads. Quand je dis access, je veux dire l’opération sur l’unité, comme volatile_var = 10 ou int temp = volatile_var (en gros écrire / lire avec des valeurs constantes). Le mot-clé volatil dans Java assure deux choses:

  1. Lors de la lecture, vous obtenez toujours la valeur dans la mémoire principale. Généralement, à des fins d’optimisation, JVM utilise des registres ou, plus généralement, des variables de stockage / d’access à la mémoire locale . Ainsi, dans un environnement multi-thread, chaque thread peut voir une copie différente de la variable. Mais le rendre volatil permet de s’assurer que l’écriture dans la variable est vidée dans la mémoire principale et que sa lecture se produit également dans la mémoire principale et donc s’assurer que le thread voit la bonne copie de la variable.
  2. L’access au volatile est automatiquement synchronisé. Ainsi, JVM assure un ordre en lecture / écriture sur la variable.

Cependant, Jon Skeet mentionne à juste titre que dans les opérations non atomiques (volatile_var = volatile + 1), des threads différents peuvent avoir un résultat inattendu.

Si un volatile ne dépend d’aucune autre variable volatile, son thread est sûr pour l’opération de lecture. En cas d’écriture volatile ne garantit pas la sécurité du fil.

Supposons que vous ayez une variable i volatile et que sa valeur dépend d’une autre variable volatile, disons j. Maintenant, Thread-1 accède à la variable j et l’incrémente et s’apprête à le mettre à jour dans la mémoire principale à partir du cache du processeur. Si le Thread-2 lit le
La variable i avant Thread-1 peut réellement mettre à jour le j dans la mémoire principale. La valeur de i sera selon l’ancienne valeur de j qui serait incorrecte. Son aussi appelé Dirty read.

Pas toujours.

Ce n’est pas un thread-safe si plusieurs threads écrivent et lisent la variable. Son thread est sûr si vous avez un seul thread d’écriture et plusieurs threads de lecteur.

Si vous recherchez Thread en toute sécurité, utilisez les classes AtomicXXX

Une petite boîte à outils de classes prenant en charge la programmation sans fil et sans locking sur des variables uniques.

Essentiellement, les classes de ce paquet étendent la notion de valeurs volatiles, de champs et d’éléments de tableau à celles qui fournissent également une opération de mise à jour conditionnelle atomique de la forme:

 boolean compareAndSet(expectedValue, updateValue); 

Reportez-vous à @teto pour répondre dans le message ci-dessous:

Volatile booléen vs AtomicBoolean

1) Si deux threads sont à la fois en train de lire et d’écrire sur une variable partagée, l’utilisation du mot-clé volatile pour cela ne suffit pas. Vous devez utiliser une synchronisation dans ce cas pour garantir que la lecture et l’écriture de la variable sont atomiques. La lecture ou l’écriture d’une variable volatile ne bloque pas la lecture ou l’écriture des threads. Pour cela, vous devez utiliser le mot-clé synchronisé autour des sections critiques.

2) Au lieu d’un bloc synchronisé, vous pouvez également utiliser l’un des nombreux types de données atomiques présents dans le package java.util.concurrent. Par exemple, AtomicLong ou AtomicReference ou l’un des autres.

Son thread est sûr si vous avez un seul thread d’écriture et plusieurs threads de lecteur.

 class Foo { private volatile Helper helper = null; public Helper getHelper() { if (helper == null) { synchronized(this) { if (helper == null) helper = new Helper(); } } return helper; } } 

Note: Si l’assistant est immuable, alors pas besoin de mot clé volatile. Ici, le singleton fonctionnera correctement.

Si le compteur est incrémenté par plusieurs threads (opération d’écriture), la réponse ne sera pas correcte. Cette condition est également illustrée par la condition de course.

 public class Counter{ private volatile int i; public int increment(){ i++; } } 

NOTE: Ici volatile ne va pas aider.