Source: author: LouisWong my.oschina.net/u/1753415/b…

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(a) {
        return value;
    }

    public void setValue(long value) {
        this.value = value;
    }

    public LongAtomTest(long value) {
        this.setValue(value);
    }

    @Override
    public void run(a) {
        int i = 0;
        while (i < 100000) {
            LongAtomTest.field = this.getValue();
            i++;
            long temp = LongAtomTest.field;
            if(temp ! =1L&& temp ! = -1L) {
                System.out.println("Error result occurred" + temp);
                System.exit(0);
            }
        }
        System.out.println("Working correctly");
    }

    public static void main(String[] args) throws InterruptedException {
        // Gets and prints 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 = newThread(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 result is 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:

  1. Lock: Identifies a variable as being owned by a thread
  2. 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 for subsequent load operations
  4. Load: Puts the value of a variable from main memory into a copy of the variable in working memory from the read operation
  5. Use: Passes the value of a variable in working memory to the execution engine, which uses it whenever the virtual machine reaches an instruction that uses the variable
  6. Assign: Assigns a value received from the execution engine to a variable in working memory. This operation is used whenever the virtual machine accesses an instruction that assigns a value to the variable
  7. Store: Passes the value of a variable in working memory to main memory for subsequent write operations
  8. Write: Writes the value of the variable obtained from the working memory by the store operation to the variable in the 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 can be nonatomic if they are not volatile. The operation can be divided into two steps, each for 32 bits.
  2. If you use volatile to modify long and double, both reads and writes are atomic
  3. For 64 – bit reference address reading and writing, all atomic operations
  4. When implementing the JVM, you are free to choose whether to read and write 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.

Recent hot articles recommended:

1.1,000+ Java Interview Questions and Answers (2021)

2. I finally got the IntelliJ IDEA activation code thanks to the open source project. How sweet!

3. Ali Mock is officially open source, killing all Mock tools on the market!

4.Spring Cloud 2020.0.0 is officially released, a new and disruptive version!

5. “Java Development Manual (Songshan version)” the latest release, quick download!

Feel good, don’t forget to click on + forward oh!