Synchronized lock mechanism-java

Synchronized is an atomic built-in lock, which is written in C++. We can't see the source code inside. It is a set of instructions. We can use this instruction to implement lock operations on objects.

Syntax: (1) Synchronization code block; (2) Synchronization method .

Object lock (monitor) mechanism:
(1) First, let's observe the lock operation of synchronized code blocks using synchronized;

package Synchronized;

public class SynchronizedTest {
    
    
    public static Object object=new Object();

    public static void main(String[] args) {
    
    
        synchronized (object){
    
    
            System.out.println("hello baby");
        }
    }
}

After disassembling, we can see the disassembled encoding information:
Insert picture description here
after executing the synchronized code block, the monitorenter instruction must be executed first, and the monitorexit instruction when exiting . After analysis, it can be seen that the key to using Synchronized for synchronization is to obtain the monitor monitor of the object. After the thread obtains the monitor, it can continue to execute, otherwise it can only wait. The acquisition process is mutually exclusive, that is, only one thread can acquire the monitor at the same time.

The above bytecode contains a monitorenter instruction and two monitorexit instructions. This is because the Java virtual machine needs to ensure that the acquired lock can be unlocked on both the normal execution path and the abnormal execution path.

(2) After executing the locking and compiling of the synchronized code block:
This mark appears in the compiled bytecode file: ACC_SYNCHRONIZED, which indicates that when entering the method, the Java virtual machine needs to perform a monitorenter operation, and when exiting the method At this time, whether it is returning normally or throwing an exception to the caller, the Java virtual machine needs to perform a monitorexit operation. (So ​​there are two monitorexit exit operations)

public class SynchronizedTest {
    
    
    public static Object object=new Object();
    public  synchronized void eat(){
    
    
        System.out.println("eat banana");
    }

    public static void main(String[] args) {
    
    
        SynchronizedTest s=new SynchronizedTest();
        s.eat();
        }
   }

The compiled result shows:
Insert picture description here

The role of monitorenter and monitorexit:

We can abstractly understand that each lock object has a lock counter and a pointer to the thread holding the lock.

When the monitorenter is executed, if the counter of the target lock object is 0, it means that it is not held by other threads. In this case, the Java virtual machine sets the holding thread of the lock object as the current thread and increments its counter by 1. In the case that the counter of the target lock object is not 0, if the thread holding the lock object is the current thread, the Java virtual machine can increase its counter by 1, otherwise it needs to wait until the holding thread releases the lock.
When the monitorexit is executed, the Java virtual machine needs to decrement the counter of the lock object by 1. When the counter decreases to 0, it means that the lock has been released.

The reason for using this counter method is to allow the same thread to repeatedly acquire the same lock . For example, if there are multiple synchronized methods in a Java class, then the mutual calls between these methods, whether directly or indirectly, will involve repeated lock operations on the same lock. Therefore, we need to design such a reentrant feature to avoid implicit constraints in programming.

Guess you like

Origin blog.csdn.net/m0_46551861/article/details/115168611