【问题标题】:Concerning volatile and synchronized关于 volatile 和 synchronized
【发布时间】:2013-10-02 13:31:48
【问题描述】:

在阅读了一堆关于这个主题的问题/文章后,我还有一件事不清楚。

据我了解(如果我错了,请纠正我)是一个变量的值可以在本地缓存到一个线程,所以如果一个线程更新该变量的值,这个变化可能对另一个不可见线。然后使用volatile 本质上是强制所有线程从同一位置读取变量的值。此外,有关该主题的所有文献都指出,对该变量进行同步将具有相同的效果。

我的问题是,我读过的任何内容都没有明确指出在 不同 变量上同步会导致相同的行为,但经常提供代码示例说明在以下两种情况下,从变量中读取将是最新的:

volatile int x;
...
int y = x;

final Object lock = new Object();
int x;
...
synchronized(lock) {
    int y = x;
}

那么问题来了:对任意变量进行同步是否会强制同步块中的每个变量访问都访问该变量的最新值?

【问题讨论】:

  • 无法回答你的问题,但我不得不说你的标题......是史诗般的。让我想起托尔金对指环王的开场白,“关于霍比特人”。

标签: java multithreading synchronized volatile


【解决方案1】:

在任何情况下同步 任意变量将强制每个变量访问 同步块以访问该块的最新值 变量?

只要该变量的写入是在同一个变量的同步下完成的,您就可以对任何变量进行同步读取。

在您的示例中,只要发生类似以下情况,那么在写入 x 之前发生的所有写入将在后续读取后可见:

synchronized(lock){
   x = 10;
}

所以到你之前的观点:

...我读过的任何内容都没有明确指出在不同的设备上同步 变量将导致同样的行为...

那是因为它不提供相同的行为。发生之前的关系在少数情况下发生,在您的情况下,两个重要的是

  1. 同一个易失性变量的写入和后续读取
  2. 同一对象上监视器的退出和后续进入

【讨论】:

    【解决方案2】:

    有一篇启发性的文章here 被提及:

    在 Java 内存模型中,volatile 字段写入之后插入了一个存储屏障和一个加载屏障 插入 在阅读之前。 ...

    请注意,没有特定于正在访问的字段。这意味着访问 any 易失性字段会为 所有 缓存变量生成障碍。

    同步具有类似的功能。

    【讨论】:

    • 这是不准确的。这是 JMM 的大多数实现的构建方式,但 JMM 本身并不能保证 => 我不会依赖它。