java - ThreadPoolExecutor.execute() 的内存可见性保证

标签 java multithreading jvm thread-safety

如果您使用 ThreadPoolExecutor 执行一个 Runnable,并且如果这个 Runnable 修改了一些共享状态,是否可以保证这些对共享状态的更改是否在提交的原始线程中可见可运行到游泳池?假设共享状态只有 1 位作者和 1 位读者。我知道当您使用返回 FutureExecutorService 时,执行 Future.get() 将保证可见性。


class State {
    private int x;
    public State(int y) { x = y; }
    public void setX(int y) { x = y; }
    public int getX() { return x; }
}

main() {
    threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...))

    final State myState = new State(1);

    threadPool.execute(new Runnable() {
        public void run() {
            myState.setX(50);
        }
    });

    while (true) {
        if (myState.getX() == 50) {
             break;
        }
        sleep();
    } // would this loop terminate?
}

最佳答案

这取决于,没有隐含的保证状态的改变会立即反射(reflect)在原始线程中,主要是因为原始线程可能有 x 值的缓存副本,它不会当另一个线程更改主内存中 x 的值时被更新。

您可以通过使用 volatile 关键字添加显式保证来解决此问题,例如:

class State {
    private volatile int x;
    public State(int y) { x = y; }
    public void setX(int y) { x = y; }
    public int getX() { return x; }
}

这告诉编译器它不能缓存 x 的值,每次程序读取 x 时它都必须检查主内存中的值。这将导致原始线程在任何其他线程修改它时立即看到 x 的新值。

更多细节在这里:

http://www.javamex.com/tutorials/synchronization_volatile.shtml

关于java - ThreadPoolExecutor.execute() 的内存可见性保证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8146218/

相关文章:

java - 将父类(super class)的对象转换为子类的对象会创建一个新对象吗?

java - 在 Android 中根据 GroupID 获取联系人

java - 单个Linux服务器上部署多tomcat服务器,每个tomcat都有独立的JVM吗?

java - 为没有用户界面的 Java 程序制作 OSX 应用程序包,在应用程序运行时保留在 Dock 中

java - 按下回车后的 JTextArea

c# - 使用 Reactive Extensions 同时处理流时如何限制缓冲

jvm - JVM、JDK、JRE、JIT的层次结构是怎样的?

scala - 我可以使用哪些工具来对 Scala 代码进行基准测试?

C++11 线程不适用于虚拟成员函数

c# - 处理异步任务时,使用await 与使用ContinueWith 有何不同?