Interviewer: Can synchronized prohibit instruction reordering? Most people will get it wrong!

instruction reordering

1. Problem description

First of all, it must be clear: instruction reordering and ordering are not the same. this point is very important.

We often say this:

  • Volatile can guarantee memory visibility and prohibit instruction reordering but cannot guarantee atomicity.
  • Synchronized can guarantee atomicity, visibility and order.

Note: The order here does not mean that instruction reordering can be prohibited.

for example:

In the double-checked singleton mode, since synchronized has been added, why do we need volatile to modify variables? If synchronized can prohibit instruction rearrangement, then volatile is completely unnecessary.

Recommend an open source and free Spring Boot practical project:

https://github.com/javastacks/spring-boot-best-practice

2. DCL code bytecode analysis instruction reordering problem

The knowledge points that need to be known first: Object obj = new Object(); This code is not an atomic operation, it is divided into three steps:

  • Apply for a space in memory, and create an object with new
  • Call the constructor of this object from new
  • Assign a reference to this object to obj
a), DCL double check code
public class MySingleton {

    private static MySingleton INSTANCE;

    private MySingleton() {
    }

    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (MySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new MySingleton();
                }
            }
        }
        return INSTANCE;
    }
}
b), the bytecode is as follows

As can be seen from the bytecode, new MySingleton();this code corresponds to the four lines of bytecodes 17, 20, 21, and 24 (line 20 is a copy of the reference and can be ignored).

  • First create a MySingleton object by opening up a space in memory on line 17.
  • Then call the object's constructor on line 21.
  • Then assign the reference of the object to the static variable INSTANCE on line 24.

The above is the execution order we expect, and we hope that each thread executes instructions in this order (this is to prohibit instruction reordering). However, in order to improve operating efficiency, the computer will optimize the order of our instructions (for example, the above order may be optimized and rearranged as: 17, 24, 21)

Problems with instruction reordering

  • In order to improve efficiency, our computer will optimize the order of our code. For example, the execution order in the t1 thread is 17, 24, 21, and the execution order in the t2 thread is 17, 21, 24 (in a single thread No matter what order of execution it is, there will be no problem).
  • When the t1 thread acquires the lock and executes object creation, it executes line 24 first, and assigns the reference of the object to the static variable INSTANCE (at this time, the object has not yet called the constructor, and the object is not yet a complete object).
  • At this time, the t2 thread starts to run. When the t2 thread executes if (INSTANCE == null)the (16th line of code) statement, the t2 thread finds that the INSTANCE is not empty. At this time, the t2 thread directly returns the INSTANCE object. But at this time, the object is still an incomplete object, and problems will occur when the t2 thread uses the object.

So there is no problem with instruction reordering in a single thread, but once it involves multi-threading, instruction reordering may bring unexpected results.

orderliness

So since synchronized cannot prohibit the reordering of instructions, what order is the order it guarantees?

Its essence is to allow multiple threads to change from parallel (concurrent) to serial calls when calling synchronized modified methods, and whoever acquires the lock will execute.

1. Code example

Both threads t1 and t2 need to obtain the singleton object, and then call the test method, and the test method is a method with a synchronization lock.

public class MySingleton {

    private static MySingleton INSTANCE;

    private MySingleton() {
    }

    public static MySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (MySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new MySingleton();
                }
            }
        }
        return INSTANCE;
    }

    public static void test(final MySingleton singleton) {
        synchronized (MySingleton.class) {
            System.out.println(singleton);
        }
    }
}

test code

public class MySingletonTest {
  // 可以看到两个线程都需要去获取单例对象,然后调用test方法,并且test方法是加了同步锁的方法
    public static void main(final String[] args) {
        new Thread(() -> {
            MySingleton instance = MySingleton.getInstance();
            MySingleton.test(instance);
        }, "t1").start();
        new Thread(() -> {
            MySingleton instance = MySingleton.getInstance();
            MySingleton.test(instance);
        }, "t2").start();
    }
}

Even if the t2 thread obtains the object that has not called the constructor, then MySingleton.test(instance);there will be no problem when calling the method in the t2 thread, because the synchronization lock is used, and each method executed with one lock becomes The serialization has changed the concurrent execution into serialization. When the t2 thread acquires the lock and executes it, t1 has already released the lock, and the instance has already been instantiated at this time. So there will be no problem.

So synchronized guarantees sequentiality refers to turning concurrent execution into serial, but it does not guarantee the reordering of internal instructions.

Source: blog.csdn.net/Hellowenpan/article/details/117750543

Recent hot article recommendation:

1. 1,000+ Java interview questions and answers (2022 latest version)

2. Brilliant! Java coroutines are coming. . .

3. Spring Boot 2.x tutorial, too comprehensive!

4. Don't fill the screen with explosions and explosions, try the decorator mode, this is the elegant way! !

5. The latest release of "Java Development Manual (Songshan Edition)", download quickly!

Feel good, don't forget to like + forward!

Guess you like

Origin blog.csdn.net/youanyyou/article/details/132563045