java - volatile 变量没有给出预期的输出

标签 java multithreading static threadpool thread-synchronization

我读到, volatile 变量副本将由所有线程共享,一旦执行完成,每个线程都会获得更新值,但是在下面使用线程池的程序中没有给出我期望的输出,任何人都可以告诉我原因吗?

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

最佳答案

观察到的结果是正确的,因为您正在创建三个单独的 Task 实例,这些实例拥有自己的 name 变量副本。

因此,尽管它们是 volatile ,但其他线程不会更新这些值,但执行特定实例的线程是正在更新v1 字段的线程。

如果v1 被设为静态,那么它就会成为class 成员,因此显然线程将更新变量v1 的相同副本。

我们可以使用 AtomicInteger 来安全地更新和获取值,而不是在 run 方法上使用 synchronized

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

关于java - volatile 变量没有给出预期的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54820903/

相关文章:

c# - 返回从未使用过的对象的构造函数是否浪费?

c++ - 在 C++ 中访问静态变量

java - 静态方法(main)如何能够捕获非静态方法(构造函数)并执行它?

java - 如何使用 DOM append 现有 XML 文件而不覆盖现有数据?

Java Jackson 2.8.3 序列化包含具有循环依赖关系的抽象对象的列表

java - 线程中的每个操作都发生在该线程中按程序顺序稍后出现的每个操作之前

c++ - 如何确定 Win32 线程是否已终止?

python - grpc python在客户端和服务器上支持多线程

java - 组合和随机化两个java数组

java - 具有正向和负向前瞻的正则表达式模式