2
votes

la variable volatile ne donne pas la sortie attendue

J'ai lu que la copie de variable volatile sera partagée par tous les threads et une fois l'exécution terminée, la valeur de mise à jour sera obtenue par chaque thread, mais dans le programme suivant utilisant le pool de threads ne donnant pas la sortie que j'attendais, n'importe qui dis moi la raison?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable{
    volatile int v1=10;

    private String name;

    public Task(String name) {
        this.name=name;
    }

    public  synchronized void  run() {
        v1=v1+10;
        System.out.println(name +"is entered "+v1);

    }

}
public class ThreadPoolTest {

    public static void main(String[] args) {
        Runnable r1 = new Task("Thread 1"); 
        Runnable r2 = new Task("Thread 2"); 
        Runnable r3 = new Task("Thread 3"); 

        ExecutorService executor = Executors.newFixedThreadPool(5);

        executor.execute(r1);
        executor.execute(r2);
        executor.execute(r3);

        executor.shutdown();  
    }
}

outPut:

Thread 1is entered 20
Thread 2is entered 20
Thread 3is entered 20

but if we change from volatile to static its giving below output:

Thread 1is entered 20
Thread 3is entered 30
Thread 2is entered 40


2 commentaires

Ce qui est tout à fait logique car vous créez 3 instances de la classe Task et son instance a sa propre variable v1. Ainsi, lorsque vous rendez ot statique, toutes les tâches partagent la même variable. C'est pourquoi ça va 20 30 40.


Ne pas changer de volatile à statique , à la place AJOUTER le statique tout en conservant le volatile (c.-à-d. Passer de «volatile» à «statique volatile»)


3 Réponses :


4
votes

Le résultat observé est correct car vous créez trois instances de Task distinctes qui ont leur propre copie de la variable name .

Ainsi, bien qu'elles soient volatiles , les valeurs ne sont pas mises à jour par d'autres threads, le thread exécutant l'instance particulière est celui qui met à jour le champ v1 .

Si le v1 est rendu statique, alors il devient un membre de class donc évidemment les threads mettront à jour la même copie de la variable v1 .

Au lieu d'utiliser synchronized sur la méthode run , nous pouvons utiliser AtomicInteger pour mettre à jour et récupérer la valeur en toute sécurité.

class Task implements Runnable{
    private final AtomicInteger v1 = new AtomicInteger(10);

    private String name;

    public void run() {
       System.out.println("Thread is: " + Thread.currentThread().getName() + " " + v1.addAndGet(10));
    }

}
public class ThreadPoolTest{

    public static void main(String[] args) {
        Runnable r1 = new Task();
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.execute(r1);
        executor.execute(r1);
        executor.execute(r1);
        executor.shutdown();
    }
}


0 commentaires

2
votes

Ceci est dû au fait que v1 est une variable d'instance et que chaque tâche a la sienne.

Donc, dans l'exemple, vous avez incrémenté v1 de différentes instances. static n'est pas non plus fiable puisque vous synchronisez sur l'instance d'une Task donc elle a toujours une condition de concurrence (par exemple, chaque thread peut lire v1 valeur de 10 même en cas de statique volatile )

Vous avez probablement besoin de AtomicInteger


1 commentaires

Oui, mieux vaut passer un AtomicInteger aux constructeurs des Runnables. Évitez les variables globales / statiques.



1
votes

Pour être bref, les variables volatiles ou atomiques sont les solutions pour résoudre l'incohérence ( erreurs de cohérence de la mémoire ) lorsque deux ou plusieurs threads tentent d'accéder à la même ressource (peut être statique / non -statique) simultanément.

https://docs.oracle.com/javase/tutorial /essential/concurrency/sync.html

Dans votre cas, vous ne partagez pas votre tâche avec plus d'un thread. donc pas besoin d'utiliser des mots clés volatils ou des variables atomiques. si vous souhaitez partager votre variable avec plus d'un thread, vous pouvez utiliser des variables atomiques sur volatile.

Que se passe-t-il alors lorsque vous ajoutez un mot-clé statique à une variable?

Les variables statiques sont disponibles pour tous les objets de cette classe.

https://docs.oracle.com/javase/tutorial /java/javaOO/classvars.html

https://docs.oracle.com/javase/tutorial /java/nutsandbolts/variables.html


0 commentaires