在Java中,长整型和双精度浮点型的写入不是原子操作吗?

37

除非变量是long或double类型,否则读写单个变量是原子的(语言保证!)。

我在阅读一门课程的幻灯片时发现了这个内容。 这个课程是关于并发性的。

有人能解释一下为什么写入long或double不是原子操作吗? 这真的让我感到惊讶。


1
1.) 什么语言/环境? 2.) 您发布的链接受到密码保护。 - Joachim Sauer
抱歉:S火狐浏览器存储了密码,我完全忘记了。 - fmsf
它表示它是语言无关的。 - fmsf
你可能想要删除链接。 - Brian Rasmussen
这些信息肯定会依赖于编程语言和环境。 - Michael Burr
7个回答

40

由于在机器代码级别上,它是一个多步操作,因此它不是原子性的。也就是说,longs和doubles比处理器的字长要长。


5
对的,在一台64位机器上,使用64位long类型,写入long类型很可能是原子性的,除非你指的是JVM或其他情况。 - Paul Tomblin
10
取决于编程语言。我很确定Java的基本数据类型在所有机器上都保证具有特定的长度。 - Tim Frey
2
.NET框架也将其“基元”设置为特定的位长度,而不是一定数量的字节。 int是Int32的同义词,其始终是32位... - Beska
3
注意:在Java中,int是32位,long是64位(不管处理器架构如何),原问题与Java有关,也许后来添加了标签。但我不确定,在64位处理器上写入是否具有原子性。这将取决于JVM到JVM。 - rents
1
@fmsf,在Java中不是这样的。长整型被定义为具有64位,与机器字长无关。 - Ole V.V.
显示剩余7条评论

30

12
这些操作在64位JVM中是原子性的,这在当今是常态。 - Amrish Pandey
3
为了支持Amrish的观点,我观看了一个有Cliff Click和Doug Lea参与的演示(小组讨论)并且Cliff提到doubles和longs在64位JVM上实际上是原子操作。因此,尽管Java内存模型表示我们需要使用volatile关键字来保证long类型的操作是原子的,但在64位JVM上不需要这么做。 - Rob Bygrave
5
@AmrishPandey 这些操作在64位JVM中是原子性的,请问您能否分享支持链接或进一步阅读的网址? - roottraveller
4
@AmrishPandey,你的观点是错误的。请阅读此回答中链接的Java规范:它明确指出,除非标记为volatile,否则不能保证对doublelong进行原子写入。JVM实现可能执行原子写入,但没有Java程序员应该依赖于此。如果存在多线程,则必须防止对半写入的64位数的错误读取。请不要将您的错误直觉发布为事实。 - Basil Bourque
2
在Java中它们不是原子性的,但在64位JVM中它们是原子性的。如果您可以忽略32位JVM,那么您可以将它们视为原子性的。当然,如果32位JVM尝试运行您的代码,则可能会观察到可能的复杂性 - Pacerier
显示剩余2条评论

6

Java中,long和double类型在32位机器上不是原子操作,在一些64位JVM上是原子操作。为什么要依赖于机器位数?因为32位机器需要进行两次写入才能完成long(因为long类型有64位)。

要了解详细信息,请阅读此处


1
它不需要进行两次写入,它可以进行两次写入;这是因为在CPU级别上有指令可以与64位寄存器的前32位(或后32位)交互。 - Eugene

3

很多程序员可能已经在《Java并发实践》的“3.1.2. 非原子的64位操作”中读到这句话。我参考了最新的JLS17.7. double和long的非原子处理,它们仍然没有声称64位jVM是现今的标准。因此,64位操作被分解成32位操作,这会破坏原子性,在多线程环境下使用会很危险,除非声明为volatile。在Java中,long和double是64位长的。因此,写入和读取操作在Java中不是原子操作。


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

1
可能是两个单独的写入操作。 - Pacerier

1

0

原子变量操作意味着任何线程都可以在没有任何垃圾的情况下从中读取/写入

对于x32和某些x64,非long/double的读/写是原子的,因为存在硬件限制。如果使用volatile,则会使其成为原子性

[原子性]


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