我不打算在这里实际回答你的问题 - 相反,我会将你重定向到我看到推荐的关于这个主题的建议的书:Java并发实践。
一个警告:如果这里有答案,预计其中相当多的答案是错误的。我不打算发布细节的原因之一是,我很确定我至少在某些方面会犯错。当我说每个认为自己可以回答这个问题的人实际上有足够的严谨性来纠正它时,我对社区没有任何不尊重的意思,这几乎是零。(Joe Duffy最近发现了一些令.NET内存模型感到惊讶的东西。如果他能弄错,像我们这样的凡人也会犯错。
我将只就一个方面提供一些见解,因为它经常被误解:
波动性和原子性之间是有区别的。人们通常认为原子写入是易失性的(即,如果写入是原子的,则无需担心内存模型)。那不是真的。
波动性是关于执行读取的一个线程(逻辑上,在源代码中)是否会“看到”另一个线程所做的更改。
原子性是关于如果看到变化,是否有机会只看到部分变化。
例如,以写入整数字段为例。这保证是原子的,但不是不稳定的。这意味着如果我们有(从foo.x = 0开始):
Thread 1: foo.x = 257;
Thread 2: int y = foo.x;
可以是 0 或 257。由于原子性约束,它不会是任何其他值(例如256或1)。但是,即使您知道在“墙时间”中线程2中的代码在线程1中的代码之后执行,也可能存在奇怪的缓存,内存访问“移动”等。使变量易失性将解决此问题。y
x
剩下的就交给真正的诚实至善的专家了。