Pet*_*eas 5 multithreading jvm memory-model happens-before vm-implementation
Java的内存模型基于强制执行规则的“先有先后”关系,但也允许在缓存失效方面优化虚拟机的实现。
例如,在以下情况下:
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
如果线程A调用method()而线程B试图在lockA内部获取method2(),则同步lockA将要求线程B在释放其锁之前,观察线程A对所有变量所做的所有更改,甚至包括之前在“代码”中更改的变量。锁定”部分。
另一方面,method3()使用另一个锁并且不强制发生关系之前的事件。这为优化创造了机会。
我的问题是虚拟机如何实现那些复杂的语义?是否在不需要缓存时避免完全刷新缓存?
它如何跟踪在哪个点哪个线程更改了哪个变量,从而仅从内存加载所需的缓存行?
您对 JVM 的期望太高了。内存模型有意只描述必须保证的内容,而不是如何实现它。某些架构具有连贯的缓存,根本不需要刷新。尽管如此,当涉及到禁止超过某一点的读取和/或写入重新排序时,可能需要采取一些措施。
\n\n但在所有情况下,这些影响都是全局的,因为保证是针对所有读取和写入进行的,而不取决于建立先发生关系的特定构造。回想一下,在释放特定锁之前发生的所有写入都发生在获取同一锁之后的所有读取之前。
\n\nJVM 不会\xe2\x80\x99t 处理happens-before关系。它通过解释(执行)代码或为其生成本机代码来处理代码。这样做时,它必须通过插入屏障或刷新来遵守内存模型,并且不重新排序超出这些屏障的读或写指令。此时,它通常会孤立地考虑代码,而不是查看其他线程在做什么。这些冲刷或障碍的影响总是全局性的。
\n\n然而,具有全局效应并不足以建立事前发生的关系。仅当一个线程保证在另一个线程保证(重新)读取值之前提交所有写入时,这种关系才存在。当两个线程在不同的对象上同步或获取/释放不同的锁时,这种顺序不存在。
\n\n对于volatile变量,您可以评估变量的值以查明其他线程是否已写入预期值并因此提交写入。在出现块的情况下synchronized,互斥会强制执行排序。因此,在synchronized块内,线程可以检查监视器保护的所有变量以评估状态,这应该是synchronized使用同一监视器的块内先前更新的结果。
由于这些影响是全局性的,一些开发人员被误导,认为只要关于时间顺序的假设是\xe2\x80\x9creasonable\xe2\x80\x9d,在不同的锁上同步就可以了,但必须考虑这样的程序代码之所以被破坏,是因为它依赖于特定实现的副作用,尤其是它的简单性。
\n\n最近的 JVM 所做的一件事是考虑纯粹本地的对象,即从未被任何其他线程看到的对象,在同步它们时可以\xe2\x80\x99t 建立发生之前的关系。因此,在这些情况下可以忽略同步的影响。我们可以期待未来更多的优化\xe2\x80\xa6
\n| 归档时间: |
|
| 查看次数: |
528 次 |
| 最近记录: |