关于volatile和synchronized

5
阅读了许多关于这个话题的问题/文章后,仍有一件事情对我不清楚。据我所知(如果我错了,请纠正),变量的值可以在本地缓存到线程中,因此如果一个线程更新该变量的值,则另一个线程可能无法看到这个更改。然后使用volatile强制所有线程从相同位置读取变量的值。此外,关于这个话题的所有文献都说明,在该变量上进行同步将具有相同的效果。
我的问题是,我所阅读的内容从未明确说明在不同变量上同步会导致相同的行为,但经常提供一个代码示例,说明在以下两种情况下从变量读取的值将是最新的:
volatile int x;
...
int y = x;

and

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

那么问题是:在任何随意变量上同步是否会强制同步块内的每个变量访问都访问该变量的最新值?

回答不了你的问题,但我必须说你的标题……太史诗了。让我想起托尔金《指环王》开头的“关于霍比特人”的章节。 - StormeHawke
2个回答

5
同步任意变量是否会强制同步代码块内每个变量的访问,以访问该变量的最新值?
只要在相同变量的同步下进行变量的写操作,您可以针对任何变量进行读取同步。在您的示例中,只要类似以下操作发生,则在后续读取之后,针对 "x" 的写入之前发生的所有写入都将可见:
synchronized(lock){
   x = 10;
}

回到你之前提到的问题:

...我读过的所有内容都没有明确说明在不同变量上进行同步会导致相同的行为...

这是因为它不会产生相同的行为。发生happens-before关系的情况有几种,其中在您的情况下最重要的有两种:

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

2
这里有一篇启发性文章(链接),提到了以下内容:
在Java内存模型中,对于一个volatile字段,在写入该字段之后会插入一个存储栅栏,并且在读取该字段之前会插入一个加载栅栏。。。
请注意,访问哪个字段都没有具体说明。这意味着访问任何volatile字段都会为所有缓存变量生成栅栏。
同步具有类似的功能。

1
那是不准确的。尽管大多数JMM的实现都是这样构建的,但JMM本身并不保证它=>我不会依赖它。 - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接