Java内存模型 - volatile 和 x86

15
我正试图理解Java volatile的本质及其语义,以及它对底层架构和指令的转换。如果我们考虑以下博客和资源:
- 为volatile生成栅栏 - 读写volatile所生成的内容 - 关于栅栏的stackoverflow问题 这是我收集到的信息:
- volatile读会在之后插入loadStore/LoadLoad屏障(x86上的LFENCE指令) - 它防止加载与后续写入/加载的重新排序 - 它应该保证加载由其他线程修改的全局状态,即在LFENCE之后,其他线程所做的状态修改对当前线程在其CPU上可见。
我难以理解的是:Java在x86上不会发出LFENCE指令,即读取volatile不会导致LFENCE。我知道x86的内存排序可以防止加载与加载/存储的重新排序,因此第二个要点已经得到了处理。但是,我认为为了使状态对此线程可见,应该发出LFENCE指令,以确保在栅栏之后执行的下一条指令之前,所有LOAD缓冲区都已被清空(根据英特尔手册)。我知道x86上有高速缓存一致性协议,但是volatile读取仍应清空缓冲区中的任何LOAD,请问这是为什么?

似乎你忘记了Java是跨平台的。 - Jacob G.
4
无论是否独立于平台,Java 实现并非完全独立于平台,因此我们仍然可以提出关于 Java 实现行为的问题。 - user2357112
LFENCE 只对弱序载入有用。X86 上的常规载入不是弱序的,因此 LFENCE 不提供额外的价值。 - pveentjer
2个回答

6

在x86上,缓冲区被固定到缓存行。如果缓存行丢失,缓冲区中的值将不会被使用。因此,没有必要对缓冲区进行栅栏或清空操作;它们所包含的值一定是最新的,因为另一个核心在未使缓存行无效之前不能修改数据。


抱歉,您的意思是我不需要使用lfence,因为当实际加载发生时,缓存行无效,那些加载缓冲区将被丢弃?也就是说,lfence会有一种懒惰的执行方式? - Bober02
2
是的,没错。缓冲区被固定到缓存行上。如果缓存行无效,缓存读取也会失效。因此,虽然x86可以预取读取,但它永远不会使用过时的值。(当然,这只是x86的特性。) - David Schwartz
其他可能在寄存器中的变量怎么办?我认为还需要一些寄存器卸载,对吧? - Bober02
@Bober02 JVM不会将volatile存储在寄存器中。 - David Schwartz
不是易失性变量 - 我们有易失性变量x,以及在写入x之前更改的其他变量。然而,在读取x的值后,所有变量的更改都是可见的。因此,那些可能已经在寄存器中的变量显然也需要被清除。 - Bober02
@Bober02 是的,你说得对。我老是忘记了Java做出了这个(在我看来有点荒谬)的实现改变。任何一个可以访问到那个volatile关键字修饰的变量的线程,都需要以某种方式进行同步。 - David Schwartz

1
X86提供TSO。因此,在硬件级别上,您可以免费获得以下屏障[LoadLoad] [LoadStore] [StoreStore]。唯一缺少的是[StoreLoad]。
加载具有获取语义。
r1=X
[LoadLoad]
[LoadStore]

一家商店具有发布语义。
[LoadStore]
[StoreStore]
Y=r2

如果您执行存储后紧接着进行加载,结果将如下所示:
[LoadStore]
[StoreStore]
Y=r2
r1=X
[LoadLoad]
[LoadStore]

问题在于加载和存储仍然可以被重新排序,因此它不是顺序一致的;而这对于Java内存模型来说是必需的。防止这种情况的唯一方法是使用[StoreLoad]。
[LoadStore]
[StoreStore]
Y=r2
[StoreLoad]
r1=X
[LoadLoad]
[LoadStore]

最合适的地方应该是将其添加到写入操作中,因为通常读取次数比写入操作频繁。因此,写入操作将变为:

[LoadStore]
[StoreStore]
Y=r2
[StoreLoad]

因为X86提供了TSO,所以以下栅栏可能是无操作的:
[LoadLoad] [LoadStore] [StoreStore]
因此,唯一相关的是[StoreLoad],可以通过MFENCElock addl %(RSP),0来实现。
LFENCE和SFENCE在这种情况下不相关。LFENCE和SFENCE用于弱排序的加载和存储(例如SSE)。
在X86上,[StoreLoad]的作用是停止执行加载,直到存储缓冲区已被清空。这将确保在存储已全局可见(已离开存储缓冲区并进入L1d)之后从内存/高速缓存读取负载。

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