Home  >  Article  >  Java  >  How to implement the synchronized lock expansion mechanism in Java

How to implement the synchronized lock expansion mechanism in Java

WBOY
WBOYforward
2023-04-28 17:13:131510browse

    synchronized

    In JDK 1.5, synchronized needs to call the monitor lock (Monitor) to implement, and the monitor lock essentially depends on the underlying layer. It is implemented by the operating system's Mutex Lock (mutex lock). When releasing and acquiring the mutex lock, it needs to be converted from user mode to kernel mode, which causes high costs and requires a long execution time. This kind of lock that relies on the operating system's Mutex Lock implementation is called a "heavyweight lock".

    What are user mode and kernel mode?

    User Mode: When the process is executing the user's own code, it is said to be in the user running state. Kernel Mode: When a task (process) executes a system call and is trapped in the kernel code, we say that the process is in the kernel running state. At this time, the processor is executing in the kernel code with the highest privilege level.

    How to implement the synchronized lock expansion mechanism in Java

    Why are we divided into kernel mode and user mode?

    Assuming that there is no distinction between kernel mode and user mode, the program can read and write hardware resources at will, such as reading, writing and allocating memory at will. In this way, if the programmer accidentally writes inappropriate content to where it should not be Where written, it is likely to cause the system to crash.

    With the distinction between user mode and kernel mode, the program will perform a series of verifications and inspections when performing an operation. Only after confirming that there is no problem can it operate the resources normally, so that it will not Worry about accidentally damaging the system, that is, The distinction between kernel mode and user mode can make the program run more safely, but at the same time, switching between the two modes will cause a certain performance overhead.

    Lock expansion

    In JDK 1.6, in order to solve the performance consumption caused by acquiring and releasing locks, the states of "biased lock" and "lightweight lock" were introduced , at this time, there are a total of 4 synchronized states:

    • No lock

    • Biased lock

    • Lightweight lock

    • Heavyweight lock

    The level of the lock is upgraded in the order mentioned above. Let’s upgrade this The process is called "lock expansion".

    How to implement the synchronized lock expansion mechanism in Java

    PS: So far, the lock upgrade is one-way, that is to say, it can only be upgraded from low to high (no lock-> ; Bias lock-> lightweight lock-> heavyweight lock), there will be no lock degradation.

    Why can lock expansion optimize the performance of synchronized? When we understand these lock states, we will naturally have the answer. Let's take a look at it together.

    Biased lock

    HotSpot The author found through research and practice that in most cases, there is no multi-thread competition for locks, and they are always acquired multiple times by the same thread. In order to allow threads to obtain the lock The cost was lower, so bias locks were introduced.

    Biased Locking means that it will be biased towards the first thread to access the lock. If only one thread accesses the synchronization lock during operation, there will be no multi-thread contention. Then the thread does not need to trigger synchronization. In this case, a bias lock will be added to the thread.

    Biased lock execution process

    When a thread accesses the synchronized code block and acquires the lock, the thread ID of the lock bias will be stored in the Mark Word of the object header, and the thread ID will be stored in the Mark Word of the object header when the thread enters and exits the synchronized block. Instead of locking and unlocking through CAS operations, it detects whether the bias lock pointing to the current thread is stored in Mark Word. If the thread ID in Mark Word is consistent with the accessed thread ID, you can directly enter the synchronization block to code. Execution, if the thread IDs are different, use CAS to try to acquire the lock. If the acquisition is successful, enter the synchronized block to execute the code. Otherwise, the lock status will be upgraded to a lightweight lock.

    Advantages of biased locks

    Biased locks are designed to minimize unnecessary lock switching without multi-thread competition, because the acquisition and release of locks rely on multiple times. CAS atomic instruction, and biased lock only needs to execute the CAS atomic instruction once when replacing the thread ID.

    Mark Word Extended Knowledge: Memory Layout

    In the HotSpot virtual machine, the layout of objects stored in memory can be divided into the following 3 areas:

    • Object Header

    • Instance Data

    • Alignment Filling(Padding)

    The object header also contains:

    • Mark Word (mark field): Our bias lock information is stored in this area.

    • Klass Pointer (Class object pointer)

    The layout of the object in memory is as follows:

    How to implement the synchronized lock expansion mechanism in Java

    In JDK 1.6, biased locking is enabled by default. You can disable biased locking through the "-XX:-UseBiasedLocking=false" command.

    Lightweight lock

    The purpose of introducing lightweight lock is to reduce the use of traditional heavyweight locks in the operating system Mutex Lock (mutex lock) without multi-thread competition. The performance consumption caused by locks. If you use Mutex Lock, each operation of acquiring and releasing a lock will cause switching between user mode and kernel mode, which will cause a huge performance overhead for the system.

    When the bias lock is turned off or multiple threads compete for the bias lock, the bias lock will be upgraded to a lightweight lock. The acquisition and release of the lightweight lock are completed through CAS, and the lock acquisition may be through A certain number of spins to complete.

    Notes

    It needs to be emphasized: Lightweight locks are not used to replace heavyweight locks. Their original intention is to use them without multi-thread competition. , Reduce the performance consumption caused by the use of traditional heavyweight locks. The scenario that lightweight locks adapt to is the situation where threads alternately execute synchronized blocks. If multiple threads access it at the same time, the lightweight lock will expand into a heavyweight lock.

    Heavyweight lock

    synchronized relies on the monitor to implement method synchronization or code block synchronization. Code block synchronization is implemented using the monitorenter and monitorexit instructions. The monitorenter instruction is compiled after Inserted at the beginning of the synchronized code block, while monitorexit is inserted at the end of the method and the exception. Any object has a Monitor associated with it. When a Monitor is held, it will be in a locked state.

    The locking code is as follows:

    public class SynchronizedToMonitorExample {
        public static void main(String[] args) {
            int count = 0;
            synchronized (SynchronizedToMonitorExample.class) {
                for (int i = 0; i < 10; i++) {
                    count++;
                }
            }
            System.out.println(count);
        }
    }

    When we compile the above code into bytecode, its content is as follows:

    How to implement the synchronized lock expansion mechanism in Java

    It can be seen from the above results that there are multiple monitorenter and monitorexit instructions in the execution of the main method. It can be seen that synchronized is implemented by relying on the Monitor monitor lock, and The monitor lock relies on the operating system's mutex lock (Mutex Lock). Each time the mutex lock is acquired and released, it will switch between user mode and kernel mode, which increases the performance overhead of the system.

    The above is the detailed content of How to implement the synchronized lock expansion mechanism in Java. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete