Is Java’s long and double Access Truly Atomic? A Deep Dive
Through a multithreaded test program, this article explores whether Java’s 64‑bit long and double types are accessed atomically on 32‑bit and 64‑bit JVMs, explains the JVM memory model rules, and shows how volatility and hardware affect atomicity.
Java long and double atomicity
Java basic types long and double are both 8 bytes; can a 32‑bit processor read/write them atomically, or does the JVM guarantee atomicity?
Is the operation on long atomic in the JVM?
First, a program is used to test the atomicity of long. The test program is as follows:
public class LongAtomTest implements Runnable {
private static long field = 0;
private volatile long value;
public long getValue() { return value; }
public void setValue(long value) { this.value = value; }
public LongAtomTest(long value) { this.setValue(value); }
@Override
public void run() {
int i = 0;
while (i < 100000) {
LongAtomTest.field = this.getValue();
i++;
long temp = LongAtomTest.field;
if (temp != 1L && temp != -1L) {
System.out.println("出现错误结果" + temp);
System.exit(0);
}
}
System.out.println("运行正确");
}
public static void main(String[] args) throws InterruptedException {
String arch = System.getProperty("sun.arch.data.model");
System.out.println(arch + "-bit");
LongAtomTest t1 = new LongAtomTest(1);
LongAtomTest t2 = new LongAtomTest(-1);
Thread T1 = new Thread(t1);
Thread T2 = new Thread(t2);
T1.start();
T2.start();
T1.join();
T2.join();
}
}The program creates two threads, t1 and t2, each repeatedly assigning 1 and -1 to the static long variable field. After each write, the thread reads the value; if the read value is neither 1 nor -1, it prints the unexpected result.
If long reads and writes were atomic, the field would only ever be 1 or -1.
Running the program on a 32‑bit JVM produces the following output:
32-bit
出现错误结果-4294967295
运行正确This shows that concurrent writes to a long can yield a value that is neither of the written values, indicating non‑atomic behavior.
Why isn’t the operation on long atomic?
The JVM memory model defines eight atomic actions: lock, unlock, read, load, use, assign, store, write.
Operations related to assignment and retrieval involve read, load, use, assign, store, and write, which are not guaranteed to be performed as a single atomic step.
On a 32‑bit operating system, the longest single operation handles 32 bits, so a 64‑bit long must be processed in two 32‑bit steps.
If the JVM wants to guarantee atomicity for long and double, it must add extra handling, but the specification permits implementations to split the operation.
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.
From the specification we can conclude:
For 64‑bit long and double without volatile, operations may not be atomic and can be split into two 32‑bit steps.
Marking long or double as volatile makes their reads and writes atomic.
Reference reads and writes are always atomic.
The JVM implementation may choose whether to make long/double atomic.
Atomic implementation is recommended.
Experimental results show that HotSpot on a 32‑bit JVM does not implement atomic long/double operations; both reads and writes are performed in two steps, leading to non‑atomic behavior.
What about a fully 64‑bit environment?
On a 64‑bit system a single operation can handle 64 bits, so long and double can be read/written atomically. Running the same test on a 64‑bit JVM repeatedly yields correct results.
64-bit
运行正确
运行正确This demonstrates that in a 64‑bit JVM the handling of long is atomic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
