这个问题在这里已经有答案了:
如果没有print语句,循环看不到其他线程更改的值(1个答案)
与system.out[duplicate](3个答案)关联的java线程的奇怪行为
25天前关门了。
我正在学习java的volatile,我的代码是这样的。
public class Test {
public static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
while(flag){
// System.out.println(flag);
}
System.out.println("end");
});
t1.start();
Thread.sleep(100);
Thread t2 = new Thread(()->{
flag = false;
System.out.println("changed");
});
t2.start();
}
}
我知道如果flag没有volatile,线程就不存在了。这是一个可见性问题。
但是如果我在while循环中编写一些代码,比如 System.out.println("")
,t1线程将读取新值并停止循环。
我知道如何使用volatile解决可见性问题,所以我的问题是:
为什么t1在写入时可以读取flag的新值 System.out.println("")
在while循环中?
1条答案
按热度按时间jexiocij1#
当您这样做时:
你将有一个空体的环,这可以导致通过自旋场所知道的东西;从源头上可以看出:
在空循环语句的条件下重复读取非易失性字段可能会导致无限循环,因为编译器优化可能会将此字段访问移出循环。
但是,通过添加语句
System.out.println(flag);
在你的循环中你要避免旋转场。尽管如此,如果t1
读这个领域flag
从缓存中获取一个值true
,仅当存储该字段值的缓存线失效,并且线程获得新的更新值时,线程才会停止flag
字段(即。,flag=false
)从主存储器。这个
volatile
确保线程读取的更新值最多flag
现场。因此flag
volatile
确保:潜在的编译器优化不会移动对字段的访问
flag
出局了。但是如果我在while循环中编写一些代码,比如system.out.println(“”),线程t1将读取新值并停止循环。
通过添加
System.out.println("")
您将避免旋入字段问题,其次,如果查看system.out.println代码:你可以看到有一个
synchronized
这将增加线程读取字段的可能性flag
不是从缓存而是从主内存。