Java中的同步的内存效应 [英] Memory effects of synchronization in Java

查看:98
本文介绍了Java中的同步的内存效应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JSR-133常见问题说:


但是同步
比互斥更多。同步
确保线程
在同步块之前或期间写入的内存
以可预测的
方式显示给其他线程,
在同一个监视器上同步。在
之后,我们退出一个同步块,我们
释放监视器,它有
的效果,将缓存刷新到主
内存,这样
线程可以看到其他
线程。在我们可以输入
同步块之前,我们获取
监视器,它的效果是
使本地处理器高速缓存
无效,因此变量将被重新加载$ ​​b $ b主存储器。然后,我们将能够通过
查看上一个版本中所有可见的
的写入。

But there is more to synchronization than mutual exclusion. Synchronization ensures that memory writes by a thread before or during a synchronized block are made visible in a predictable manner to other threads which synchronize on the same monitor. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.

还记得阅读,在现代的Sun VMs无争议的同步是便宜。我有点困惑的这个说法。考虑下面的代码:

I also remember reading that on modern Sun VMs uncontended synchronizations are cheap. I am a little confused by this claim. Consider code like:

class Foo {
    int x = 1;
    int y = 1;
    ..
    synchronized (aLock) {
        x = x + 1;
    }
}

更新到x需要同步,的锁清除y的值还从缓存?我不能想象是这样的情况,因为如果它是真的,像锁条纹的技术可能不会帮助。或者,JVM可以可靠地分析代码,以确保y不会在使用相同锁的另一个同步块中修改,因此在进入同步块时,不会在缓存中转储y的值?

Updates to x need the synchronization, but does the acquisition of the lock clear the value of y also from the cache? I can't imagine that to be the case, because if it were true, techniques like lock striping might not help. Alternatively can the JVM reliably analyze the code to ensure that y is not modified in another synchronized block using the same lock and hence not dump the value of y in cache when entering the synchronized block?

推荐答案

JSR-133的解释太多了。 Java存储器模型根据诸如可见性,原子性,发生先前关系等事物而被正式定义,这解释了什么线程必须必须看什么,必须发生在使用精确(数学)定义的模型的其他动作和其他关系之前。没有正式定义的行为可以是随机的,或者在某些硬件和JVM实现中的实际定义 - 但是当然你不应该依赖于它,因为它可能在将来改变,你永远不能确定除非你编写JVM并且熟知硬件语义,否则它是首先定义的。

JSR-133 goes too far in its explanation. The Java memory model is formally defined in terms of things like visibility, atomicity, happens-before relationships and so on, which explains exactly what threads must see what, what actions must occur before other actions and other relationships using a precisely (mathematically) defined model. Behavior which isn't formally defined could be random, or well-defined in practice on some hardware and JVM implementation - but of course you should never rely on this, as it might change in the future, and you could never really be sure that it was well-defined in the first place unless you wrote the JVM and were well-aware of the hardware semantics.

所以你引用的文本不是正式描述什么Java保证,而是描述具有非常弱的存储器排序和可见性保证的一些假设架构可以如何使用高速缓存刷新来满足Java存储器模型要求。关于高速缓存刷新,主存储器等的任何实际讨论显然不适用于Java,因为这些概念不存在于抽象语言和存储器模型规范中。

So the text that you quoted is not formally describing what Java guarantees, but rather is describing how some hypothetical architecture which had very weak memory ordering and visibility guarantees could satisfy the Java memory model requirements using cache flushing. Any actual discussion of cache flushing, main memory and so on is clearly not generally applicable to Java as these concepts don't exist in the abstract language and memory model spec.

在实践中,存储器模型提供的保证比完全刷新弱得多 - 具有每个原子,并发相关或锁定操作刷新整个高速缓存将是非常昂贵的 - 并且这几乎从未在实践中完成。相反,使用特殊的原子CPU操作,有时结合内存屏障说明,这有助于确保内存可见性和排序。因此,通过注意第一个是真的,第二个不是 - Java存储器模型不需要完全刷新(并且在实践中不发生刷新),来解决在廉价无争用同步和完全刷新高速缓存之间的明显不一致。

In practice, the guarantees offered by the memory model are much weaker than a full flush - having every atomic, concurrency-related or lock operation flush the entire cache would be prohibitively expensive - and this is almost never done in practice. Rather, special atomic CPU operations are used, sometimes in combination with memory barrier instructions, which help ensure memory visibility and ordering. So the apparent inconsistency between cheap uncontended synchronization and "fully flushing the cache" is resolved by noting that the first is true and the second is not - no full flush is required by the Java memory model (and no flush occurs in practice).

如果形式的内存模型有点太重,不能消化(你不会孤单),你也可以深入了解这个主题,看看< a href =http://gee.cs.oswego.edu/dl/jmm/cookbook.html =nofollow noreferrer> Doug Lea的食谱,实际上是在JSR-133 FAQ中链接的,但从具体的硬件角度出发,因为它是为编译器作者。在那里,他们谈论了特定操作(包括同步)需要什么障碍 - 并且讨论的障碍很容易映射到实际的硬件。大多数实际映射在食谱中讨论。

If the formal memory model is a bit too heavy to digest (you wouldn't be alone), you can also dive deeper into this topic by taking a look at Doug Lea's cookbook, which is in fact linked in the JSR-133 FAQ, but comes at the issue from a concrete hardware perspective, since it is intended for compiler writers. There, they talk about exactly what barriers are needed for particular operations, including synchronization - and the barriers discussed there can pretty easily be mapped to actual hardware. Much of the actual mapping is discussed right in the cookbook.

这篇关于Java中的同步的内存效应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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