正在 64 位 VM 上写入引用原子读取/写入引用始终是原子的AtomicReference

2022-08-31 21:03:16

java内存模型要求编写a是原子的:也就是说,如果你在一个线程中向它写入一个值(由4个字节组成),并在另一个线程中读取它,你将获得所有字节或无,但永远不会得到2个新字节和2个旧字节等。int

对于 不保证这一点。在这里,写入先前持有的变量可能会导致另一个线程读取或 .long0x112233445566778800x1122334400000000x0000000055667788

现在,规范不要求对象引用是 int 或长号。出于类型安全原因,我怀疑它们保证以原子方式写入,但在64位VM上,这些引用很可能是64位值(仅内存地址)。

现在这是我的问题:

  • 是否有任何内存模型规格涵盖此内容(我没有找到)?
  • 长写入是否在 64 位 VM 上被怀疑为原子写入?
  • 是否强制 VM 将引用映射到 32 位?

问候, 斯蒂芬


答案 1

读取/写入引用始终是原子的

参见JLS第17.7节:双倍和长原子处理

出于 Java 编程语言内存模型的目的,对非易失性长整型或双精度值的单次写入被视为两次单独的写入:每 32 位半部分一次写入。这可能会导致线程从一次写入中看到 64 位值的前 32 位,从另一次写入中看到第二个 32 位。

易失性长整型和双精度值的写入和读取始终是原子的。

对引用的写入和读取始终是原子的,无论它们是作为 32 位还是 64 位值实现的。

某些实现可能会发现,将 64 位长整型或双精度值上的单个写入操作拆分为相邻 32 位值上的两个写入操作很方便。为了提高效率,这种行为是特定于实现的;Java 虚拟机的实现可以自由地以原子方式或分两部分对长整型值和双精度值执行写入操作。

鼓励实现 Java 虚拟机,以避免在可能的情况下拆分 64 位值。鼓励程序员将共享的 64 位值声明为易失性或正确同步其程序以避免可能的复杂情况。

(着重号后加)

AtomicReference

如果要在旧值和新值之间进行协调,或者想要特定的内存效果,请使用类 AtomicReference

例如,AtomicReference::getAndSet 在以原子方式设置新值时返回旧值,从而消除了另一个线程在两个步骤之间进行干预的任何可能性。使用易失性内存语义


答案 2