【问题标题】:What is the scope of cache flushing required by Java's synchronize keyword?Java synchronized 关键字要求的缓存刷新范围是什么?
【发布时间】:2009-05-06 01:46:13
【问题描述】:

我今天整天研究Java内存模型,以详细了解Java 5之前的JMM存在的问题以及Java 5中实现的JSR-133所做的更改。

我似乎找不到明确的答案是特定同步所需的缓存失效和刷新的范围。

在进入任何同步代码部分时必须使所有 CPU 寄存器和缓存无效,并在离开时全部刷新到主 RAM,或者 JVM 是否允许仅使实际读取的变量无效,并仅刷新在同步块期间实际写入的变量代码?

如果是前者,为什么 JMM 如此迂腐地坚持只在两个线程之间发生内存屏障,而这两个线程在完全相同的对象上同步?

如果是后者,是否有任何好的文档来解释如何完成此操作的详细信息? (我认为底层实现必须在同步块开始时在 CPU 级别设置“绕过缓存”标志并在结束时清除它,但我可能方式偏离基础。 )

【问题讨论】:

    标签: java synchronization


    【解决方案1】:

    Java Memory model 上有非常好的技术讲座。如果你不喜欢 Wideos google 'happens before' 在 Java 内存模型的上下文中。

    如果发生在关系之前,基本上所有写入对其他线程都是可见的,让我们假设线程 A 写入字段 X,线程 B 从中读取,因此发生之前是在写入和读取之间建立结束如果:

    • x 不稳定
    • 对 x 的写入受到从 x 读取的同一个锁的保护
    • 也许更多。

    所以我认为第二个选项是正确的,他们是如何实现的,我不知道。

    【讨论】:

    • 技术讲座链接已损坏。可能是this one
    【解决方案2】:

    您需要了解,5.0 之前的 JMM 从未真正完全实现过,因为它实际上并不可行。

    所以在 5.0 之前,您在技术上确实必须将所有内容都写到共享内存中。在 1.5(实际上是 1.4)中,这是放宽的。特别是,如果锁无法逃脱线程,则 JVM 有权将其视为 nop。此外,可以合并一个解锁,然后是同一个锁的一个锁,这对于旧的 JMM 是不正确的。对于逃逸锁,JVM 通常不得不悲观并刷新超过技术上的必要。

    【讨论】:

    • 谢谢汤姆;但我实际上主要对无效和刷新内存缓存的范围感兴趣。
    【解决方案3】:

    我建议你从:

    【讨论】:

    • 抱歉,链接中出现了一个流浪字符 -- 现已修复
    • 附注邮件列表是可搜索的!
    • 哦,是的,无论你做什么,都要大量阅读,因为这是相当复杂的东西。这就是为什么你有 Java 而不是汇编程序的 JVM 和程序,所以一般来说,你不必太担心所有这些细节(尽管我承认我很书呆子也觉得它很有趣)。