50

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

对于long. 在这里,写入之前0x1122334455667788保存的变量0可能会导致另一个线程读取0x1122334400000000x0000000055667788.

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

现在这是我的问题:

  • 是否有任何涵盖此的内存模型规格(我还没有找到)?
  • 长写操作在 64 位虚拟机上是否具有原子性?
  • 虚拟机是否强制将引用映射到 32 位?

问候, 史蒂芬

4

1 回答 1

63

读/写引用总是原子的

请参阅JLS 第 17.7 节:double 和 long 的非原子处理

出于 Java 编程语言内存模型的目的,对非易失性 long 或 double 值的单次写入被视为两次单独的写入:每个 32 位一半。这可能导致线程从一次写入中看到 64 位值的前 32 位,而从另一次写入中看到后 32 位。

volatile long 和 double 值的写入和读取始终是原子的。

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

一些实现可能会发现将 64 位 long 或 double 值的单个写入操作分成对相邻 32 位值的两个写入操作很方便。为了效率起见,这种行为是特定于实现的;Java 虚拟机的实现可以自由地以原子方式或分两部分执行对 long 和 double 值的写入。

鼓励 Java 虚拟机的实现尽可能避免拆分 64 位值。鼓励程序员将共享的 64 位值声明为 volatile 或正确同步他们的程序以避免可能的并发症。

(重点补充)

AtomicReference

如果您想在新旧值之间进行协调,或者想要特定的记忆效果,请使用 class AtomicReference

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

于 2010-04-05T01:36:36.157 回答