Volatile 变量的更新值对其他线程不可见

Volatile variable's updated value is not visible to other threads

以下代码片段使用多个线程使用 AtomicInteger 计数到 1 亿。我有 10 个 Writer threads 来模拟写入争用,还有一个 单个 Reader 线程 来模拟读取争用。 Writer 和 Reader 还共享一个 volatile 布尔变量 作为 毒丸

但是,只有 Reader 线程能够退出,而 Writers 则不能。尽管将变量声明为 volatile,为什么 Reader 线程无法看到更新后的值?

public class AtomicRunnerV2 {

    private static final int THREADS = 10;
    private static final Integer MAX_COUNT = 100_000_000;

    public static void main(String[] args) throws Exception {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        Boolean data = new Boolean(false);
        ExecutorService executorService = Executors.newFixedThreadPool(THREADS + 1);
        for (int i = 0; i < THREADS; i++) {
            executorService.submit(new Writer(atomicInteger, data));
        }
        executorService.submit(new Reader(atomicInteger, data));
        executorService.shutdown();
    }

    static class Writer implements Runnable {

        private AtomicInteger integer;
        private volatile Boolean data;

        Writer(final AtomicInteger integer, Boolean data) {
            this.integer = integer;
            this.data = data;
        }

        @Override public void run() {
            while (!data) {
                integer.incrementAndGet();
            }
            System.out.println("count " + integer.get() + " from WRITER!");
        }
    }

    static class Reader implements Runnable {

        private AtomicInteger integer;
        private volatile Boolean data;

        Reader(final AtomicInteger integer, Boolean data) {
            this.integer = integer;
            this.data = data;
        }

        @Override public void run() {
            while (!data) {
                if (integer.get() >= MAX_COUNT) {
                    data = true;
                }
            }
            System.out.println("count " + integer.get() + " from READER!");
        }
    }
}

P.S:如果我将布尔值包装在一个对象中,它就可以工作。

您的 volatile boolean data 不是参考,我认为您是想在这里建议,而是一份副本。所以 Reader 中的数据永远不会被设置为 false。如果您在 Reader 中使用 Writer.data(并使其成为 public),这应该有效。

布尔值不可变的

data = true;

Writer 中的上述行实质上创建了一个新的布尔实例,从而导致 Reader 永远不会看到新值,因为在它们的布尔引用中没有 "updated"。

通过用如下所示的自定义 class 替换我代码中出现的所有布尔值来对此进行测试,并且 Reader 线程能够看到更新后的值。

static class MyBoolean {

    private boolean value;

    MyBoolean(final boolean value) {
        this.value = value;
    }

    boolean isValue() {
        return value;
    }

    void setValue(final boolean value) {
        this.value = value;
    }
}