【问题标题】:Java happend-before in synchronized blockJava 发生在同步块之前
【发布时间】:2011-11-26 14:29:19
【问题描述】:

我需要一些帮助来理解 Java 内存模型。以下是一个通用示例来掌握基本概念:

Image 我有一个名为Shared 的对象实例和两个线程AB。此外,还有某种Queue 与同步的puttake

线程A 修改Shared-instance beforein put 方法。

问题1:当B通过同步的take-方法获得Shared-object实例时,A所有变化是可见的?

问题 2:一旦A 离开同步的put 方法,就会刷新内存缓存(Shared 上的所有更改都是可见的)。如果wait()put 方法中被A 调用,会发生什么?即使A 尚未退出synchronized 方法,B 是否也会看到对Shared 所做的更改?调用wait()时缓存是否也被刷新?

【问题讨论】:

  • 非常混乱的问题。也许一些代码示例。例如,队列如何改变put方法中传递的对象?

标签: java synchronization monitor synchronized java-memory-model


【解决方案1】:

答案 1:是的。因为 take() 和 put() 都是同步的。所以在 B 可以执行 take() 之前,A 应该已经离开了同步块,离开同步块意味着刷新内存缓存(内存栅栏/屏障)。

答案 2:是的。因为当调用 wait() 时,线程必须交出锁,这将再次导致内存刷新。

编辑:我认为您所追求的是 cache-write-to-memory 是否发生在同步块退出或锁定释放时。答案是cache-write-to-memory 发生在释放锁时

【讨论】:

    【解决方案2】:

    第一个问题的答案是肯定的,因为同步点(存在于 put 和 take 中)引入了隐式记忆栅栏。

    对于第二个问题,取决于 A 调用等待是在对象添加到 Shared 之前还是之后。如果是之前,那么显然 shared 没有任何变化,所以 B 没有什么新东西可看。

    编辑:如果 A 调用之后等待,则更改是可见的,因为您必须在添加之前获取锁,然后在等待时释放它,这也会引入栅栏。

    所以这两种情况的答案都是肯定的。

    【讨论】:

    • 谢谢,A 首先更改 Shared,然后调用 wait()。它在队列实例上调用等待。我只是不确定调用等待是否算作“退出同步块”。因为只有在退出同步块时才能保证内存刷新。明白我在追求什么吗? :-)
    【解决方案3】:

    A 还没有退出同步方法?调用wait()时缓存是否也刷新了?

    引用JSR 133 (Java Memory Model) FAQ - What does synchronization do?

    退出同步块后,我们释放监视器,这具有将缓存刷新到主内存的效果,因此该线程所做的写入可以对其他线程可见。在我们进入同步块之前,我们获取了监视器,它具有使本地处理器缓存无效的效果,以便从主内存重新加载变量。然后,我们将能够看到以前版本中可见的所有写入。

    它表示在释放监视器时将缓存刷新到内存。请注意,当监视器在退出同步块时被释放时,它也会在调用等待方法时被释放。因此,我希望更改在 #wait() 调用上被刷新,并被另一个线程拾取,前提是它在同一个监视器上稍早等待。

    【讨论】:

      猜你喜欢
      • 2013-08-07
      • 1970-01-01
      • 2022-12-10
      • 1970-01-01
      • 1970-01-01
      • 2011-12-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-06
      相关资源
      最近更新 更多