web-dev-qa-db-fra.com

Est-ce qu'un int volatile en Java thread-safe?

Est-ce qu'une version volatile int est compatible avec les threads Java? Autrement dit, peut-on lire et écrire en toute sécurité sans verrouillage?

49
shawn

Oui, vous pouvez le lire et l'écrire en toute sécurité - mais vous ne pouvez rien faire de complexe, comme l'incrémenter en toute sécurité, car c'est un cycle de lecture/modification/écriture. Il y a aussi la question de la façon dont il interagit avec l'accès à d'autres variables.

La nature précise de volatile est franchement déroutante (voir le section du modèle de mémoire du JLS pour plus de détails ) - Je le ferais personnellement En règle générale, utilisez AtomicInteger à la place, comme moyen plus simple de vous assurer que je comprends bien.

65
Jon Skeet

pour pouvoir être lu et écrit en toute sécurité sans verrouillage?

Oui, une lecture donnera 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 "happen-before" dans l'exécution.

A partir de la spécification du langage Java Chapitre 17: Filetage et verrous

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

En d’autres termes, lorsqu’il s’agit de variables volatiles, il n’est pas nécessaire de synchroniser explicitement (introduire une relation passe-avant) avec le mot clé synchronized afin de s’assurer que le thread obtient la dernière valeur écrite dans la variable.

Comme le souligne Jon Skeet, l'utilisation de variables volatiles est limitée et vous devriez en général envisager d'utiliser les classes du package Java.util.concurrent à la place.

6
aioobe

L'accès à volatile int en Java sera thread-safe. Quand je dis accès, je parle de l’unité qui s’exécute, comme volatile_var = 10 ou int temp = volatile_var (essentiellement écriture/lecture avec des valeurs constantes). Un mot clé volatile en Java garantit deux choses:

  1. Lors de la lecture, vous obtenez toujours la valeur dans la mémoire principale. En règle générale, à des fins d’optimisation, la JVM utilise des registres ou plus généralement mémoire locale stockage des variables foe/access. Ainsi, dans un environnement multi-thread, chaque thread peut voir une copie différente de la variable. Mais le rendre volatile garantit que l’écriture dans la variable est vidée dans la mémoire principale et lue dans la mémoire principale se produit également à partir de la mémoire principale, ce qui permet de s’assurer que le thread voit à droite la copie de la variable.
  2. L'accès au volatile est automatiquement synchronisé. JVM garantit donc un ordre en lecture/écriture dans la variable.

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

2
Saurabh

1) Si deux threads lisent et écrivent à la fois sur une variable partagée, utiliser le mot-clé volatile pour cela ne suffit pas. Dans ce cas, vous devez utiliser un synchronisé 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 les fils en lecture ou en écriture. Pour ce faire, vous devez utiliser le mot-clé synchronized autour des sections critiques.

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

La sécurité des threads est assurée si vous avez un 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;
}
}

Remarque: Si helper est immuable, aucun mot-clé volatile n’est alors nécessaire. Ici, singleton fonctionnera correctement. 

En cas de compteur incrémenté de plusieurs threads (opération d'écriture lecture), la réponse ne sera pas correcte. Cette condition est également illustrée par la condition de concurrence.

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

NOTE: Ici, volatile ne va pas aider.

0
Rahul Saxena

Si une variable volatile ne dépend d'aucune autre variable volatile, son thread est sécurisé pour une opération de lecture. En cas d'écriture volatile ne garantit pas la sécurité du thread.

Supposons que vous avez une variable i qui est volatile et que sa valeur dépend d'une autre variable volatile, telle que j. À présent, Thread-1 accède à la variable j et l'incrémente. Elle est sur le point de la mettre à jour dans la mémoire principale à partir du cache de la CPU. Au cas où le Thread-2 lit le
variable i avant que Thread-1 puisse réellement mettre à jour le j dans la mémoire principale. La valeur de i correspondra à l'ancienne valeur de j qui serait incorrecte. Son aussi appelé Dirty read.

0
Ajay Verma

Pas toujours. 

Ce n'est pas thread-safe si plusieurs threads écrivent et lisent la variable. La sécurité des threads est assurée si vous avez un thread d'écriture et plusieurs threads de lecteur. 

Si vous recherchez un fil en toute sécurité, utilisez AtomicXXX classes

Un petit ensemble de classes de classes prenant en charge la programmation thread-safe sans verrou sur des variables uniques. 

En substance, les classes de ce package étendent la notion de valeurs, champs et éléments de tableau instables à ceux qui fournissent également une opération de mise à jour conditionnelle atomique du formulaire

boolean compareAndSet(expectedValue, updateValue);

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

Volatile boolean vs AtomicBoolean

0
Ravindra babu