问题:
在32位机器上对 Long/Double 型变量进行加减操作会存在并发问题
原因分析:
线程切换带来的原子性问题
非 volatile 类型的 long 和 double 型变量是 8 字节 64 位的, 32 位机器读或写这个变量的时候把它们分成两个 32 位操作,可能一个线程读取了某个值的高 32 位,低 32 位被另一个线程修改了。
所有 Java 官方推荐最好把 long/double 变量声明为 volatile 或是同步加锁 synchronized 以避免并发问题
官方文档 Chapter 17. Threads and Locks 章节说明了此类问题:
java官方文档链接
以下是关于此问题文档描述内容:
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.
解决方案:
把 long/double 变量声明为 volatile 或是同步加锁 synchronized