java并发编程,线程间共享值
我是并发编程的初学者,我想确切地理解为什么当我在get()
中注释sleep(1)
时,这个程序没有结束
我的第一个想法是,睡眠(1)将手放回Main
线程,也许忙碌的等待与此有关
public class Rdv<V> {
private V value;
public void set(V value) {
Objects.requireNonNull(value);
this.value = value;
}
public V get() throws InterruptedException {
while(value == null) {
Thread.sleep(1); // then comment this line !
}
return value;
}
public static void main(String[] args) throws InterruptedException {
Rdv<String> rendezVous = new Rdv<>();
new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
rendezVous.set("hello");
}).start();
System.out.println(rendezVous.get());
}
}
# 1 楼答案
首先也是最重要的一点是,这个计划被严重破坏了。即使在睡眠状态下,也不能保证它会终止。可能会,但可能不会
问题在于,value字段不是易失性的,并且在获取/设置值时不使用synchronized或其他锁。这意味着不能保证一个线程会看到另一个线程的变化!应该停止程序的write-to值对于正在等待的线程可能永远都不可见。有了睡眠,一切正常,因为Java是在解释模式下运行的。没有睡眠,即时编译器就有时间启动并优化代码。它发现while循环可以被重写为一个更高效的版本,它可以做同样的事情:永远循环。这就是它的作用
最简单的修复方法是将value字段声明为volatile。然后Java知道它可能会改变,并避免优化读取
短版本,除非您很了解Java内存模型,否则始终同步对线程之间共享的数据的访问。安全总比后悔好