并发编程,线程间共享值
Concurrent programming, sharing values between thread
我是并发编程的初学者,我想确切地理解为什么当我在get()
中评论sleep(1)
时这个程序没有结束
我的第一个想法是,sleep(1) 将手还给了 Main
线程,也许 Busy waiting 与 ?
有关
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());
}
}
首先,该程序严重损坏。不能保证它会在睡眠时终止。可能会,但也可能不会。
问题是值字段不是易变的,当您 get/set 值时您不使用同步锁或其他锁。这意味着不能保证一个线程会看到另一个线程更改的内容!应该停止程序的写入值可能对正在等待的线程永远不可见。有了 sleep,一切正常,因为 Java 在解释模式下是 运行。没有睡眠,即时编译器就有时间启动并优化代码。它看到 while 循环可以重写为一个更高效的版本,它做同样的事情:永远循环。这就是它的作用。
最简单的解决方法是将值字段声明为可变的。然后 Java 知道它可能会改变并避免优化读取。
简短版本,除非您非常了解 Java 内存模型,否则始终同步对线程间共享数据的访问。安全总比后悔好!
我是并发编程的初学者,我想确切地理解为什么当我在get()
中评论sleep(1)
时这个程序没有结束
我的第一个想法是,sleep(1) 将手还给了 Main
线程,也许 Busy waiting 与 ?
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());
}
}
首先,该程序严重损坏。不能保证它会在睡眠时终止。可能会,但也可能不会。
问题是值字段不是易变的,当您 get/set 值时您不使用同步锁或其他锁。这意味着不能保证一个线程会看到另一个线程更改的内容!应该停止程序的写入值可能对正在等待的线程永远不可见。有了 sleep,一切正常,因为 Java 在解释模式下是 运行。没有睡眠,即时编译器就有时间启动并优化代码。它看到 while 循环可以重写为一个更高效的版本,它做同样的事情:永远循环。这就是它的作用。
最简单的解决方法是将值字段声明为可变的。然后 Java 知道它可能会改变并避免优化读取。
简短版本,除非您非常了解 Java 内存模型,否则始终同步对线程间共享数据的访问。安全总比后悔好!