是否在32位机器上使用Java原子进行64位分配?

时间:2010-08-11 23:33:28

标签: java multithreading concurrency

如果我有这样的代码 -

long x;
x  = 0xFFFFFFFFL;


如果我在32位机器上运行此代码,它是否保证是原子的,或者读取x的不同线程是否可能得到不完整/垃圾值?

4 个答案:

答案 0 :(得分:47)

以下是简短摘要:

  • 对于参考,读/写始终原子(即使在64位实现中!)
  • 对于intcharbyteshortbooleanfloat,读/写始终 atomic
  • 对于doublelong,如果它们是volatile,则读取/写入始终原子

因此,只有读/写可能不是原子的异常:

  • 对于doublelong,如果他们 NOT 宣布为volatile,则他们 NOT GUARANTEED 是原子的

因此,就读/写共享数据的原子性而言,您只需要volatile任意doublelong。无论在实际实现中使用了多少位,其他所有内容都已保证是原子的。


关于规范

以下是此处转载的相关部分,以供快速参考:

  

JLS 17.7 Non-atomic Treatment of double and long

     

某些实现可能会发现将64位longdouble值上的单个写操作划分为相邻32位值的两个写操作很方便。为了效率,这种行为是特定于实现的; Java虚拟机可以原子地或分两部分对longdouble值进行写入。

     

出于Java编程语言内存模型的目的,对非volatile longdouble值的单个写入被视为两个单独的写入:每个32位半写一个。这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况。 volatile longdouble值的写入和读取始终是原子的。对引用的写入和读取始终是原子的,无论它们是实现为32位还是64位值。

     

鼓励VM实现者尽可能避免拆分64位值。建议程序员将共享的64位值声明为volatile或正确同步其程序以避免可能的复杂情况。

另见

相关问题

答案 1 :(得分:11)

不,他们不是。 64位存储被视为两个独立的32位存储。因此,在并发环境中,变量可以具有一个写入的高32和另一个写入的低32,显然不是线程安全的。

答案 2 :(得分:9)

Java虚拟机规范的第8.4节规定,未声明为volatile的double或long被视为两个32位变量,用于加载,存储,读取和写入操作。

此外,未定义编码方式和两个32位操作的顺序。

规范确实鼓励实现使操作成为原子,但它们不需要它。

答案 3 :(得分:8)

如果变量是volatile,则读/写保证是原子的,但如果变量是非易失性的则不是。

  

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

     

出于Java编程语言内存模型的目的,a   单次写入非易失性长或   double值被视为两个   单独写入:每个32位一个   半。这可能导致一种情况   线程看到前32位的位置   一次写入的64位值,和   另一个写入的第二个32位。   写入和读取volatile和long   double值总是原子的。

JLS 17.7 - Non-atomic Treatment of double and long

当多个线程在没有同步的情况下访问long值时,必须使用volatile来确保一个线程所做的更改对其他线程可见,并确保读/写是原子的。