in
Java Basics -String, StringBuiler, and StringBufferThread safety was mentioned in thread safety, so today we’ll talk about the source of concurrency problems.

Atomicity problems caused by thread switching

Either one or more operations are performed in full and without interruption by any factor, or none of them are performed at all.

A classic example is bank account transfers:

For example, transferring $1000 from account A to account B must involve two operations: subtracting $1000 from account A and adding $1000 to account B. These two operations must be atomic to ensure that there are no unexpected problems.

The same is true when we manipulate data, such as I = I +1; It’s reading the value of I, calculating I, writing I. This line of code is not atomic in Java.

Visibility issues due to CPU cache

When multiple threads access the same variable, one thread modifies the value of the variable, and the other threads immediately see the changed value.

If the two threads are on different cpus, thread A and thread B execute simultaneously, and the shared variable V is cached from main memory into local memory. Thread A has modified the shared variable V, which has not yet been written to main memory, and thread B has also modified the variable V, which is invisible to each other. So when they flush the value of V into main memory, one thread must override the other thread’s result. This is visibility.

Order problems caused by compilation optimization

The order in which a program is executed is the order in which the code is executed.

Generally speaking, in order to improve the efficiency of the program, the processor may optimize the input code. It does not guarantee that the execution sequence of each statement in the program is the same as that in the code, but it will ensure that the final execution result of the program is the same as that in the sequence of the code execution. As follows:

int a = 10; Int r = 2; // statement 2 a = a + 3; // statement 3 r = a*a; / / 4

Because of the reordering, he could have executed the order 2-1-3-4, 1-3-2-4, but never 2-1-4-3, because that breaks the dependency. Obviously, reordering is not a problem for single-threaded applications, but not for multithreaded applications, so we need to consider this when we’re programming multithreaded applications. Ex. :

    int a = 0;
    boolean flag = false;

    public void write() {
        a = 1;  //1
        flag = true; //2
    }

    public void read() {
        if (flag) { // 3
            int b = a * a; //4
        }
    }

In the preceding code, thread A executes write() and thread B executes read(). If flag=true is the first instruction to be reordered, then thread B switches to execute, and the result is incorrect.

Double check locking mechanism is thread safe

conclusion

Atomicity, visibility, and order all lead to concurrency problems, and all concurrency problems revolve around these three characteristics.