首页 > 解决方案 > 由一个线程写入然后由另一个线程读取的Java对象的实例字段是否必须是易失的?

问题描述

我用 Java8 编写代码,我想使用一个线程,然后通过一个可变对象捕获线程创建的结果。代码如下所示:

public class MyTest {

    public static void main(String[] args) throws InterruptedException {
        MutableString mutableString = new MutableString();

        Thread thread = new Thread(
                () -> mutableString.value = "value_from_another_thread");
        thread.start();
        thread.join();

        assert "value_from_another_thread".equals(mutableString.value);
    }

    private static class MutableString {
        String value; // Does this have to be volatile or should I use AtomicReference instead of MutableString?
    }
}

似乎它在我的开发笔记本电脑上运行良好,但有没有可能此代码在某些环境中无法正常运行?为了安全起见,我应该使用volatilevalue字段还是替换MutableString该类AtomicReference

编辑:

如果CountDownLatch使用 a 而不是thread.join()怎么办?它会改变什么吗?

public class MyTest {

    public static void main(String[] args) throws InterruptedException {
        MutableString mutableString = new MutableString();
        CountDownLatch latch = new CountDownLatch(1);
        MyThread myThread = new MyThread(latch, mutableString);

        myThread.start();
        latch.await();

        assert "value_from_another_thread".equals(mutableString.value);
    }

    private static class MyThread extends Thread {

        private final CountDownLatch latch;
        private final MutableString mutableString;

        MyThread(CountDownLatch latch, MutableString mutableString) {
            this.latch = latch;
            this.mutableString = mutableString;
        }

        @Override
        public void run() {
            mutableString.value = "value_from_another_thread";
            latch.countDown();
        }
    }

    private static class MutableString {
        String value; // Does this have to be volatile or should I use AtomicReference instead of MutableString?
    }
}

标签: javamultithreadingthread-safety

解决方案


调用线程停止和连接完成之间的关系之前发生过。因此,连接将看到线程所做的任何事情。因此不需要额外的同步。

https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.4

使用倒计时锁存器提供了类似的排序保证。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html 寻找内存一致性效果。

就我个人而言,我不会太聪明。除非您正在编写非常高性能的代码,并且您有一些带有 volatile 写入的紧密循环,否则添加 volatile 不会对您的应用程序产生太大的性能影响。所以我宁愿保守一点,增加易失性。


推荐阅读