我正在学习JDK9内存模型。
看完演讲后
Java Memory Model Unlearning Experience
并阅读论文
Using JDK 9 Memory Order Modes。
我对某些概念感到困惑。
对于第一个问题,论文说
It is almost never a good idea to use bare spins waiting for values of variables. Use Thread.onSpinWait, Thread.yield, and/or blocking synchronization to better cope with the fact that "eventually" can be a long time, especially when there are more threads than cores on a system.
因此,如果我编写代码:
// shared variable I and VarHandle I_HANDLE which referred to I
public static int I = 0;
public static final VarHandle I_HANDLE;
// Thread-1
I_HANDLE.setOpaque(1);
// Thread-2
while((int) I_HANDLE.getOpaque() == 0){
}
线程2最终终止了,但可能在很长时间之后终止了?如果是这样,是否有任何最小的方法来保证线程2立即看到线程1进行的修改? (发布/获取? volatile ?)
最佳答案
没有像“立即”这样的更新。甚至电力也以有限的速度运动。通常,在特定时间段内要求可感知的效果就像在要求操作的特定执行时间一样。不能保证,因为它们是JVM无法更改的基础体系结构的属性。
当然,实际上,JVM开发人员试图使操作尽可能快,而作为程序员,对您而言重要的是,对于更新的线程间可见性,没有不透明的写入方法没有比这更快的选择了。较强的访问模式不会更改更新显示的速度,它们会为读取和写入的重新排序增加其他限制。
因此,在您的示例中,更新将在架构和系统负载允许的情况下尽快显示出来1,但不要求提供实际数字。没有人可以说需要多长时间。如果需要时间量方面的保证,则需要特殊的(“实时”)实现,该实现可以为您提供Java内存模型之外的其他保证。
1举一个实际的例子:线程1和2可能竞争同一个CPU。线程1写入值,并在切换任务之前继续在操作系统特定的时间运行(并且甚至不能保证线程2是下一个任务)。这意味着从挂钟时间和线程1在写入后的进程来看,都可能花费相当长的时间。当然,与此同时,其他线程在其他CPU内核上也可能会取得很大进步。但是也有可能线程2在线程1提交写入之前进行了轮询,这是导致线程1没有机会写入新值的原因。因此,您应该使用onSpinWait
或yield
标记此类轮询循环,以使执行环境有机会防止此类情况发生。有关这两者之间的区别的讨论,请参见this Q&A。
关于java - 如何理解JDK9的内存模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65896858/