Atomicity of Long and double in Java

In Java, long and double are both 8 bytes long and 8 bytes long. 32-bit processors cannot read or write them all at once.

Are operations on Longs in the JVM atomic operations?

First, the atomicity of long is judged by a procedure. The test procedure 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 ! {system.out.println (" error "+ temp); System.exit(0); }} system.out.println (" run correctly "); } public static void main(String[] args) throws InterruptedException {// Get and print whether the current JVM is 32-bit or 64-bit 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(); }}Copy the code

As you can see, there are two threads in the program t1, T2; T1 and T2 continuously assign static variable field of type long to 1 and -1 respectively. Each assignment to T1 and t2 reads the value of field, and prints the value of field if it is neither 1 nor -1.

If the write and read operations on long are atomic, then the value of field can only be 1 or -1

The running results are as follows:

32-bit error result -4294967295 The operation is correctCopy the code

As you can see, when threads T1 and T2 write to long at the same time, long appears as a value that is neither written by T1 nor written by T2.

Presumably, operations on Longs in the JVM are not atomic operations.

Why isn’t the operation on long atomic?

There are eight atomic operations defined in the JVM memory model:

Unclock: Releases a variable from its exclusive state so that it can be locked by other threads. 3. Read: transfers the value of a variable from main memory to working memory. Load: puts the value of a variable in main memory into a copy of a variable in working memory. Use: passes the value of a variable in working memory to the execution engine. Assign: assigns a value received from the execution engine to a variable in the working memory. Assign: assigns a value to a variable in the working memory whenever the virtual opportunity assigns a value to a variable in the main memory. 8. Write: Writes the value of the variable from the working memory to the variable in main memory

Associated value among them, and the assignment, including read, load, the use, assign, store, write

According to this rule, long reads and writes are atomic operations, contrary to our practice, why this problem?

For 32-bit operating systems, the maximum length that can be processed in a single operation is 32 bits, and the long type is 8-byte 64-bit, so it takes two instructions to read and write a long (i.e., read and write 32 bits at a time).

If the JVM wants to keep long and double reads and writes atomically, it must do extra processing. So, does the JVM take extra care of this situation?

Refer to the Java language specification documentation: JLS-17 non-atomic Treatment of Double and Long to address this issue

  • 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 regulations, we can know:

1. Operations on 64-bit longs and doubles may not be atomic if they are not volatile. The operation can be divided into two steps, each for 32 bits. 2. If long and double are volatile, both read and write are atomic operations 3. Read and write to 64-bit reference addresses are atomic operations 4. When implementing the JVM, you are free to choose whether to write and read long and double as atomic operations 5. It is recommended that the JVM implement atomic operations

From the results of the program, the 32-bit HotSpot does not implement long and double reads and writes as atomic operations. The read and write operations are divided into two operations, each reading and writing 32 bits. Because of this strategy, 64-bit longs and doubles are read and written without atomic operations.

What if the hardware, operating system, and JVM are all 64-bit?

For 64-bit environments, 64-bit data can be manipulated in a single operation, that is, the entire 64bit of long or double can be read and written in a single operation. So we can guess that reading and writing long and double in 64-bit environments might be atomic operations. After switching to a 64-bit JVM and running it several times, the results were correct

64-bit running correctly Running correctlyCopy the code

The results show that long processing is atomic in 64-bit virtual machines.

Author | | LouisWong source my.oschina.net/u/1753415/b…