我感兴趣的是一个线程正在等待以更改while
循环中的变量:
while (myFlag == false) {
// do smth
}
重复无数次。
与此同时,另一个帖子已更改此变量的值:
myFlag = true;
如果此变量不是volatile,读者线程是否可以看到更改另一个线程中变量值的结果?一般来说,据我所知,它永远不会发生。还是我错了?然后在什么情况下,第一个线程可以看到变量的变化并退出循环?这可以不使用volatile
关键字吗?在这种情况下,处理器缓存的大小是否起作用?
请解释并帮助我理解!提前谢谢!!
答案 0 :(得分:8)
如果此变量不是易失性的,那么读者线程是否可以看到更改另一个线程中变量值的结果?
可以能够,是的。只是它不会肯定看到变化。
一般来说,据我所知,它永远不会发生。
不,事实并非如此。
您正在写一个变量,然后在另一个线程中读取它。您是否看到它将取决于所涉及的确切处理器和内存架构。如果没有任何内存障碍,您就不会保证看到新值 - 但您肯定不能保证不看到它。
答案 1 :(得分:4)
如果此变量不是易失性的,那么读者线程是否可以看到更改另一个线程中变量值的结果?
我想对@ Jon的优秀答案进行一些扩展。
Java内存模型表示如果特定线程中的所有内存超过任何内存屏障,它将被更新。读取障碍导致特定线程中的所有高速缓存内存都从中央内存更新,写入障碍导致本地线程更改被写入中央。
因此,如果您的线程写入另一个volatile
字段或进入synchronized
块,则会导致您的标志在中央内存中更新。如果读取线程从另一个volatile
字段读取,或者在更新发生后在synchronized
部分中输入// do smth
块,则会看到更新。当发生这种情况时,或者如果写入/读取顺序正确发生,您就不能依赖。如果您的线程没有其他内存同步点,那么永远不会发生。
修改强>
鉴于下面的讨论,我现在已经在各种不同的问题中进行了几次讨论,我想我可能会更多地扩展我的答案。 Java语言提供的保证与其内存模型和JVM实现的实际情况之间存在很大差异。 JLS和JMM定义了内存障碍,并且仅在相同字段上的volatile
读取和写入之间以及上的synchronized
锁定之间讨论“先发生”保证相同的对象。
但是,在我听说的所有体系结构中,强制执行内存同步的内存屏障的实现是不是字段或对象特定的。当在volatile
字段上进行读取并且在特定线程上跨越读取障碍时,将使用所有中央内存更新它,而不仅仅是特定{{1}有问题的字段。 volatile
次写入也是如此。在对volatile
字段进行写入后,将本地线程的所有更新写入中央内存,而不仅仅是字段。 JLS 所做的保证的是,指令无法在volatile
访问权限之后重新排序。
因此,如果线程A已写入volatile
字段,那么所有更新,即使那些不标记为volatile
的更新也将写入中央内存。完成此操作后,如果thread-B从另一个volatile
字段读取,则他将看到所有线程A的更新,即使那些未标记为volatile
的更新。同样,围绕这些事件的时间有 no 保证,但如果它们以该顺序发生,则两个线程将被更新。