Java虚拟机如何实现“先于发生"?记忆模型? [英] How does a Java virtual machine implement the "happens-before" memory model?

查看:150
本文介绍了Java虚拟机如何实现“先于发生"?记忆模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java的内存模型基于强制执行规则的先有先后"关系,但也允许在缓存无效方面对虚拟机的实现进行优化.

Java's memory model is based on "happens-before" relationship that enforces rules but also allows for optimization in the virtual machine's implementation in terms of cache invalidation.

例如在以下情况下:

// 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尝试在method2()中获取lockA,则在lockA上的同步将要求线程B观察线程A在对其之前的所有变量进行的所有更改.释放其锁定,甚至包括锁定之前的代码"部分中更改的变量.

if thread A calls method() and thread B tries to acquire lockA inside method2(), then the synchronization on lockA will require that thread B observes all changes that thread A made to all of its variables prior to releasing its lock, even the variables that were changed in the "code before lock" section.

另一方面,method3()使用另一个锁,并且不强制发生关系之前的事件.这为优化创造了机会.

On the other hand, method3() uses another lock and doesn't enforce a happens-before relatation. This creates opportunity for optimization.

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

My question is how does the virtual machine implements those complex semantics? Does it avoid a full flush of the cache when it is not needed?

它如何跟踪哪个变量在哪个点由哪个线程更改了,从而仅从内存中加载所需的缓存行?

How does it track which variables did change by which thread at what point, so that it only loads from memory just the cache-lines needed?

推荐答案

您期望对JVM的想法过于笼统.内存模型只是故意描述必须保证的内容,而不是必须实现的方式.某些架构具有一致的缓存,根本不需要刷新.不过,在某些情况下,可能需要采取一些措施来禁止对读和/或写进行重新排序.

You expect a too high-level thinking of a JVM. The memory model is intentionally only describing what has to be guaranteed, instead of how it has to be implemented. Certain architectures have coherent caches that don’t need to be flushed at all. Still, there might be actions required when it comes to forbid reordering of reads and/or writes beyond a certain point.

但是在所有情况下,这些影响都是 global ,因为对所有读取和写入都做出了保证,而不依赖于建立事前发生关系的特定构造.回想一下, all 的写入发生在释放特定的锁之前-在获取相同的锁之后 all 的读取之前.

But in all cases, these effects are global as the guarantees are made for all reads and writes, not depending on the particular construct which establishes the happens-before relationship. Recall, all writes happening before releasing a particular lock happen-before all reads after acquiring the same lock.

JVM根本不处理先发生关系.它通过解释(执行)代码或为代码生成本机代码来处理代码.这样做时,它必须通过插入障碍或刷新,并且不要重新排序超出这些障碍的读取或写入指令来遵守内存模型.在这一点上,它通常孤立地考虑代码,而不关注其他线程在做什么.这些潮红或壁垒的影响始终是全球性的.

The JVM doesn’t process happens-before relationships at all. It processes code, either by interpreting (executing) it or by generating native code for it. When doing so, it has to obey the memory model by inserting barriers or flushes and by not reordering read or write instructions beyond these barriers. At this point, it usually considers the code in isolation, not looking at what other threads are doing. The effect of these flushes or barriers is always global.

但是,具有全局影响不足以建立先发生后关系.仅当保证一个线程在所有之前前提交所有写操作时,此关系才存在,并保证另一个线程(重新)读取值.当两个线程在不同的对象上同步或获取/释放不同的锁时,此排序不存在.

However, having a global effect is not sufficient for establishing a happens-before relationship. This relationship only exists, when a thread is guaranteed to commit all writes before the other thread is guaranteed to (re-)read the values. This ordering does not exist, when two threads synchronize on different objects or acquire/release different locks.

对于volatile变量,您可以评估变量的值以找出其他线程是否已写入期望值并因此提交了写入.在synchronized块的情况下,互斥强制执行排序.因此,在synchronized块中,线程可以检查监视器保护的所有变量以评估状态,这应该是使用同一监视器的synchronized块中先前更新的结果.

In case of volatile variables, you can evaluate the value of the variable to find out, whether the other thread has written the expected value and hence committed the writes. In case of a synchronized block, the mutual exclusion enforces an ordering. So within the synchronized block, a thread can examine all variables guarded by the monitor to evaluate the state, which should be the result of a previous update within a synchronized block using the same monitor.

由于这些影响是全球性的,因此,只要对时间顺序的假设是合理的",一些开发人员就会误以为在不同的锁上进行同步是可以的,但是由于依赖于这种程序代码,因此必须考虑将其破坏特定实现的副作用,尤其是其简单性.

Since these effects are global, some developers were misguided into thinking that synchronizing on different locks was ok, as long as the assumption about a time ordering is "reasonable", but such program code must be considered broken as it is relying on side effects of a particular implementation, especially its simplicity.

最近的JVM所做的一件事是,考虑到纯本地对象(即其他线程从未见过的对象)在它们上进行同步时无法建立事前发生的关系.因此,在这些情况下可以消除同步的影响.我们可以期待将来会有更多优化……

One thing that recent JVMs do, is to consider that objects which are purely local, i.e. never seen by any other thread, can’t establish a happens-before relationship when synchronizing on them. Therefore, the effects of synchronization can be elided in these cases. We can expect more optimizations in the future…

这篇关于Java虚拟机如何实现“先于发生"?记忆模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆