long或double在32位机器上的并发问题


在网上看到这么句话:
在32位的机器上对long型变量进行加减操作存在并发隐患
查了下,发现很多帖子有这句话,但又没有说明清楚,莫非不额外进行并发安全控制,在64位对long的加减就没问题?在32位对int的加减就没问题?加或减?这都明显是两个操作,肯定有并发问题啊,不废话吗。

看官方说法:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7
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.
按照oracle官方文档的说法是对非volatile long或double变量的写入会变成两个32位写入操作,这可能导致一个线程写入第一个32位后,另一个线程看到了这个只写了一半值的变量。

那这个“写入”对应到java代码中是指啥?
是指基础类型的赋值
long x = 1L;
后面又说对引用的写入无论在32位机器还是64位上都是保证原子的。
“引用的写入”又指啥?
是指对象变量的赋值
Object o = new Object();
所以“在32位的机器上对long型变量进行加减操作存在并发隐患”这句话应该改成“在32位的机器上对long型变量进行写入操作存在并发隐患”

但这种隐患很难见到,因为多线程中共享变量怎么都得会加volatile或加锁,不然就算是原子操作也会有另外的问题,如可见性。
2023/10/22 22:20
回首页