переменная переменная не дает ожидаемого выхода - PullRequest
0 голосов
/ 22 февраля 2019

Я прочитал, что копия изменяемой переменной будет совместно использоваться всеми потоками, и после завершения выполнения значение обновления будет получено каждым потоком, но в следующей программе, использующей пул потоков, не дающий ожидаемого результата, может любойскажите мне причину?

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

Ответы [ 3 ]

0 голосов
/ 22 февраля 2019

Это потому, что v1 является переменной экземпляра и каждая задача имеет свою собственную.

Итак, в примере вы увеличили v1 различных экземпляров.static также не является надежным, поскольку вы синхронизируете экземпляр Task, поэтому он все еще имеет состояние состязания (например, каждый поток может прочитать значение v1, равное 10, даже в случае static volatile)

Вероятно, вам нужно AtomicInteger

0 голосов
/ 22 февраля 2019

Короче говоря, энергозависимые или атомарные переменные являются решениями для устранения несоответствия ( Ошибки согласованности памяти ), когда два или более потоков пытаются получить доступ к одному и тому же ресурсу (может быть статическим или нефиксированным).static) одновременно.

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

В вашем случае, вы не делите свою задачу более чем с одним потоком. , поэтому нет необходимости использовать volatileключевое слово или атомные переменные.если вы хотите поделиться своей переменной с более чем одним потоком, то вы можете использовать атомарные переменные вместо volatile.

, что произойдет, когда вы добавите статическое ключевое слово в переменную?

статические переменныедоступно всем объектам этого класса.

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

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

0 голосов
/ 22 февраля 2019

Наблюдаемый результат верен, поскольку вы создаете три отдельных экземпляра Task, которые имеют свою собственную копию переменной name.

Таким образом, хотя они volatile, значения не обновляются другими потоками, поток, выполняющий конкретный экземпляр, является тем, который обновляет поле v1.

Если v1становится статическим, затем становится членом class, поэтому, очевидно, потоки обновят ту же копию переменной v1.

Вместо использования synchronized в методе run, мы можем использоватьAtomicInteger для безопасного обновления и извлечения значения.

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();
    }
}
...