正在 64 位 VM 上编写参考原子

发布于 2024-08-28 04:52:02 字数 545 浏览 6 评论 0原文

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

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

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

现在我的问题是:

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

问候, 史蒂芬

The java memory model mandates that writing a int is atomic: That is, if you write a value to it (consisting of 4 bytes) in one thread and read it in another, you will get all bytes or none, but never 2 new bytes and 2 old bytes or such.

This is not guaranteed for long. Here, writing 0x1122334455667788 to a variable holding 0 before could result in another thread reading 0x112233440000000 or 0x0000000055667788.

Now the specification does not mandate object references to be either int or long-sized. For type safety reasons I suspect they are guaranteed to be written atomically, but on a 64bit VM these references could be very well 64bit values (merely memory addresses).

Now here are my questions:

  • Are there any memory model specs covering this (that I haven't found)?
  • Are long-writes suspect to be atomic on 64bit VMs?
  • Are VMs forced to map references to 32bit?

Regards,
Steffen

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

此生挚爱伱 2024-09-04 04:52:02

读/写引用始终是原子的

请参阅 JLS 部分17.7:double和long的非原子处理

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

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

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

某些实现可能会发现划分单个写入很方便
对 64 位长整型或双精度值的操作分为两个写入操作
相邻的 32 位值。为了效率的缘故,这种行为是
具体实施; Java 虚拟机的实现
可以自由地以原子方式或以方式执行对 long 和 double 值的写入
两部分。

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

(强调)

AtomicReference

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

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

Reading/writing references always atomic

See JLS section 17.7: Non-atomic Treatment of double and long

For the purposes of the Java programming language memory model, a
single write to a non-volatile long or double value is treated as two
separate writes: one to each 32-bit half. This can result in a
situation where a thread sees the first 32 bits of a 64-bit value from
one write, and the second 32 bits from another write.

Writes and reads of volatile long and double values are always atomic.

Writes to and reads of references are always atomic, regardless of
whether they are implemented as 32-bit or 64-bit values.

Some implementations may find it convenient to divide a single write
action on a 64-bit long or double value into two write actions on
adjacent 32-bit values. For efficiency's sake, this behavior is
implementation-specific; an implementation of the Java Virtual Machine
is free to perform writes to long and double values atomically or in
two parts.

Implementations of the Java Virtual Machine are encouraged to avoid
splitting 64-bit values where possible. Programmers are encouraged to
declare shared 64-bit values as volatile or synchronize their programs
correctly to avoid possible complications.

(Emphasis added)

AtomicReference

If you want to coordinate between old and new values, or want specific memory effects, use the class AtomicReference.

For example, AtomicReference::getAndSet returns the old value while setting the new value atomically, eliminating any chance of another thread having intervened between the two steps. Uses volatile memory semantics.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文