看看这段代码:
public class VolatileTest {
private static boolean ready = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run() {
ready = true;
System.out.println("t2 thread should stop!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
while(!ready){
System.out.println("invoking..");
}
System.out.println("I was finished");
}
};
t1.start();
t2.start();
}
}
我认为这段代码的结果可能是:
t2 thread should stop!
invoking..
I was finished
因为在多线程中,当t1将'ready'变量修改为true时,我让t1 sleep 。目前,我认为,对于 t2 来说,“准备好”变量是错误的!因为t1线程没有停止,所以t1中的变量在t2中不可见。
但事实上..我测试了很多次。结果总是这样:
我的想法是错的吗?
最佳答案
首先,尽管调用了您的类 VolatileTest
,但您实际上并没有在代码中的任何地方使用 volatile
。
由于 ready
变量未声明为 volatile
并且您在没有任何显式同步的情况下访问它,因此行为未指定。具体来说,JLS 没有说明线程 1 中对 ready
变量进行的赋值在线程 2 中是否可见。
事实上,甚至不能保证线程 1 的 run()
方法会在线程 2 的 run()
方法之前被调用。
现在看来,您的代码(如所写的!)的行为方式与 true
的写入始终立即可见一致。但是,无法保证“始终”实际上是始终,或者在每个 Java 平台上都是如此。
如果与 sleep 相关的系统调用在调度第二个线程之前触发内存缓存刷新,我不会感到惊讶。这足以导致一致的行为。此外,由于 println
调用,可能会出现偶然的同步1。然而,这些并不是您应该依赖的效果。
1 - 在 System.out
的输出流堆栈中的某个位置,println
调用可能会同步流的共享数据结构。根据事件的顺序,这可能会产生在写入和读取事件之间插入发生在关系的效果。
关于java 当我调用 Thread.sleep() 时,数据的可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48258119/