如何理解JDK9内存模型?

我正在学习 JDK9 内存模型。

在观看Java Memory Model Unlearning Experience演讲

并阅读
Using JDK 9 Memory Order Modes 一文后。

我对一些概念感到困惑。

  1. 不透明是否立即保证可见性

  2. 如何理解论文中的偏序全序

对于第一个问题,论文说

使用等待变量值的空自旋几乎从来都不是一个好主意。使用 Thread.onSpinWait、Thread.yield 和/或阻塞同步来更好地应对“最终”可能需要很长时间的事实,尤其是当系统上的线程数多于内核数时。

所以如果我写代码:

// 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 的修改?(发布/获取?易变?)

回答

没有像“立即”更新这样的东西。甚至电力也以有限的速度移动。通常,要求在特定时间跨度内可感知的效果就像要求操作的特定执行时间。两者都不能保证,因为它们是 JVM 无法更改的底层架构的属性。

实际上,当然,JVM 开发人员试图使操作尽可能快,而对您而言,作为程序员,最重要的是,关于更新的线程间可见性,没有比不透明写入更快的替代方法。更强的访问模式不会改变更新变得可见的速度,它们为读取和写入的重新排序添加了额外的约束。

因此,在您的示例中,随着体系结构和系统负载允许1 的速度,更新将变得可见,但不要要求实际数字。没有人能说需要多长时间。如果您需要在时间量方面的保证,您需要一个特殊的(“实时”)实现,它可以为您提供 Java 内存模型之外的额外保证。


1举一个实际场景:线程 1 和 2 可能会竞争同一个 CPU。线程 1 写入值并在任务切换之前继续运行操作系统特定的时间(甚至不能保证线程 2 是下一个)。这意味着可能会流逝相当长的时间,无论是挂钟时间还是写入后线程 1 的进度。当然,其他线程也可能同时在其他 CPU 核上取得很大进展。但也有可能在线程 1 提交写入之前线程 2 的轮询是线程 1 没有机会写入新值的原因。这就是为什么你应该用onSpinWait或标记这样的轮询循环yield,让执行环境有机会防止这种情况发生。看到这个问答 讨论两者之间的区别。


以上是如何理解JDK9内存模型?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>