java - 由一个线程写入然后由另一个线程读取的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?
}
}
似乎它在我的开发笔记本电脑上运行良好,但有没有可能此代码在某些环境中无法正常运行?为了安全起见,我应该使用volatile
该value
字段还是替换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?
}
}
解决方案
调用线程停止和连接完成之间的关系之前发生过。因此,连接将看到线程所做的任何事情。因此不需要额外的同步。
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 不会对您的应用程序产生太大的性能影响。所以我宁愿保守一点,增加易失性。
推荐阅读
- bash - 使用 Azure CLI 通过 bash 创建托管实例
- ios - 将 Ipad 应用程序缩放到更大的 Ipad 屏幕尺寸
- php - Ubuntu 18.04 - 为什么会出现这些错误?
- javascript - 向下滚动到锚点后,当页面加载时,为什么页面会跳回顶部?
- android - 正确实现 RecyclerView 适配器的点击监听器
- python - Python - 按日期透视日志数据
- java - 如何设置 ControlFx SpreadsheetView 的角
- xml - XSLT - 比赛和分组时间
- sql - PowerApps 数据源更改为存储过程
- r - 计算具有成功/失败组合计数的二项式 GLMM 的 brier 分数