gpt4 book ai didi

multithreading - Java虚拟机如何实现 "happens-before"内存模型?

转载 作者:行者123 更新时间:2023-12-04 06:38:43 24 4
gpt4 key购买 nike

Java 的内存模型基于“happens-before”关系,它强制执行规则,但也允许在缓存失效方面优化虚拟机的实现。

例如在以下情况下:

// thread A
private void method() {
//code before lock
synchronized (lockA) {
//code inside
}
}

// thread B
private void method2() {
//code before lock
synchronized (lockA) {
//code inside
}
}

// thread B
private void method3() {
//code before lock
synchronized (lockB) {
//code inside
}
}

如果线程 A 调用 method()线程 B 尝试获取 lockAmethod2() ,然后在 lockA 上同步将要求线程 B 在释放锁之前观察线程 A 对其所有变量所做的所有更改,即使是在“锁前代码”部分中更改的变量。

另一方面, method3()使用另一个锁并且不强制发生先发生关系。这为优化创造了机会。

我的问题是虚拟机如何实现那些复杂的语义?它是否避免在不需要时完全刷新缓存?

它如何跟踪哪些变量在什么时候被哪个线程改变了,以便它只从内存中加载需要的缓存行?

最佳答案

您期望对 JVM 有过高层次的思考。内存模型有意仅描述必须保证的内容,而不是必须如何实现。某些架构具有完全不需要刷新的一致缓存。尽管如此,在禁止超过某个点的读取和/或写入重新排序时,可能需要采取一些措施。

但在所有情况下,这些影响都是全局的,因为对所有读取和写入都做出了保证,而不取决于建立先发生关系的特定结构。回想一下,在释放特定锁之前发生的所有写操作都发生在获得相同锁之后的所有读操作之前。

JVM 根本不处理发生之前的关系。它通过解释(执行)代码或为其生成 native 代码来处理代码。这样做时,它必须通过插入屏障或刷新并且不重新排序超出这些屏障的读取或写入指令来遵守内存模型。此时,它通常会孤立地考虑代码,而不是查看其他线程在做什么。这些冲洗或障碍的影响始终是全局性的。

然而,具有全局效应不足以建立先发生关系。只有当一个线程保证在另一个线程保证(重新)读取值之前提交所有写入时,才存在这种关系。当两个线程在不同的对象上同步或获取/释放不同的锁时,此顺序不存在。

如果是 volatile变量,您可以评估变量的值以找出其他线程是否已写入预期值并因此提交写入。如果是 synchronized块,互斥强制执行排序。所以在synchronized内块,线程可以检查由监视器保护的所有变量来评估状态,这应该是 synchronized 中先前更新的结果。块使用相同的监视器。

由于这些影响是全局的,一些开发人员误以为同步不同的锁是可以的,只要关于时间顺序的假设是“合理的”,但是这样的程序代码必须被认为是破坏的,因为它依赖于一个特定的实现,尤其是它的简单性。

最近的 JVM 做的一件事是考虑纯粹本地的对象,即任何其他线程从未见过的对象,在同步它们时不能建立发生之前的关系。因此,在这些情况下可以消除同步的影响。我们可以期待 future 有更多优化……

关于multithreading - Java虚拟机如何实现 "happens-before"内存模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32845755/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com