这可能是因为两种挥发性变量a
和b
过于接近对方,他们属于在同一高速缓存行; 尽管cpu A
仅读取/写入变量a
,而cpuB
仅读取/写入变量b
,但它们仍通过同一高速缓存行彼此耦合。这些问题称为 虚假共享 。
在您的示例中,我们有两种分配方案:
new Thread new Thread
new Container vs new Thread
new Thread ....
new Container new Container
.... new Container
在第一种方案中,两个volatile变量几乎不可能彼此接近。在第二种方案中,几乎可以肯定是这种情况。
cpu缓存不能使用单个单词;相反,它们处理高速缓存行。高速缓存行是连续的内存块,例如64个相邻字节。通常,这很好- 如果cpu访问了某个单元,则很有可能也会访问相邻的单元。除您的示例外,该假设不仅无效,而且有害。
假设a
和b
属于同一缓存行L
。cpu A
更新时a
,它会通知其他L
脏的cpu 。由于BL
也正在缓存,因为它正在工作b
,所以B
必须删除其cached L
。因此,下次B
需要读取时b
,必须重新加载L
,这是昂贵的。
如果B
必须访问主内存以进行重新加载,这将是非常昂贵的,通常速度要慢100倍。
幸运的是,A
并B
可以直接对新值,而无需通过主内存去沟通。但是,这需要花费额外的时间。
为了验证这一理论,您可以在中填充额外的128个字节Container
,以使两个的volatile变量Container
不会落在同一高速缓存行中。那么您应该观察到这两个方案执行大约需要相同的时间。
经验教训:通常,cpu假定相邻变量是相关的。如果我们想要自变量,则最好将它们彼此远离。