Make writing a habit together! This is the third day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Want to know how synchronized works? How does synchronized work? Synchronized locks are implemented using the JVM’s built-in Monitor, which in turn relies on the operating system’s Mutex lock.

The monitor

A monitor is a concept or mechanism that ensures that only one thread can execute a given area of code at any one time.

A monitor is like a building with a special room that can only be occupied by one thread at a time. A thread can monopolize all data in a room from the time it enters the room to the time it leaves the room. Entering the building is entering the monitor, entering the room is acquiring the monitor, owning the room alone is owning the monitor, Exiting the room is called releasing the Monitor, and exiting the building is called exiting the Monitor.

Strictly speaking, the concepts of monitor and lock are different, but many places refer to each other as well.

The underlying implementation

Let’s add a synchronized block to the code and see how it works at the bytecode level. Example 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); }}Copy the code

When we compile the above code into bytecode, the result looks like this:Monitorenter and Monitorexit add two monitorenter and monitorexit directives to the main method.

  • Monitorenter: Enters the monitor.
  • Monitorexit: Exits the monitor.

Synchronized relies on Monitor to implement synchronized.

Execute the process

In Java, synchronized is an unfair and reentrant lock. The so-called unfair lock refers to that threads do not obtain the lock in a first-come-first-come order, but compete with each other to obtain the lock at random. A reentrant lock means that once a thread has acquired the lock, it can be acquired again. These are the prerequisites for understanding what comes next. In HotSpot virtual machine, the bottom layer of Monitor is implemented by C++, its implementation object is ObjectMonitor, ObjectMonitor structure is implemented as follows:

ObjectMonitor::ObjectMonitor() {  
  _header       = NULL;  
  _count       = 0;  
  _waiters      = 0,  
  _recursions   = 0;       // The number of threads reentrant
  _object       = NULL;  
  _owner        = NULL;    // Identifies the thread that owns the monitor
  _WaitSet      = NULL;    _WaitSet is the first node in the list
  _WaitSetLock  = 0 ;  
  _Responsible  = NULL ;  
  _succ         = NULL ;  
  _cxq          = NULL ;    // multi-threaded contention lock entry is a one-way linked list
  FreeNext      = NULL ;  
  _EntryList    = NULL ;    //_owner wakes up the thread node from the bidirectional looping list. _EntryList is the first node
  _SpinFreq     = 0 ;  
  _SpinClock    = 0 ;  
  OwnerIsThread = 0 ;  
} 
Copy the code

There are several key attributes in the above code:

  • _count: Counts the number of times the thread acquired the lock (that is, how many times the thread acquired the lock before and after).
  • _recursions: number of lock reentrant times.
  • _owner: The Owner Owner, which is The thread that holds The ObjectMonitor object;
  • _EntryList: Monitoring set of EntryList, which stores the queue of blocked threads. In multi-threading, unsuccessful threads will enter the EntryList queue.
  • _WaitSet: A WaitSet of waiting threads that are in the wait state and enter the WaitSet queue after executing the wait() method.

The monitor performs the following flow:

  1. The thread attempts to obtain the lock through CAS. If it succeeds, the _OWNER field is set to the current thread, indicating that the current thread already holds the lock, and the _RECURsions reentrant number property is set to +1. If it fails, spin CAS attempts to acquire the lock, and if it still fails, the current thread is placed on the EntryList monitoring queue (blocked).
  2. When the thread holding the lock executes the wait method, the thread releases the lock, restores the owner variable to null, and places the thread in the WaitSet waiting queue to be awakened.
  3. When notify is called, a random thread in the WaitSet queue is woken up, and when notifyAll is called, all WaitSet threads are woken up to try to acquire the lock.
  4. After the thread has released the lock, it wakes up all threads in the EntryList to try to acquire the lock.

The above is the execution process of the monitor, as shown in the figure below:

conclusion

Synchronized locks are implemented through the JVM’s built-in Monitor, which in turn relies on the operating system’s Mutex lock. The JVM monitor executes as follows: the thread attempts to acquire the lock by spinning CAS, enters the EntrySet collection if it fails, and owns the lock if it succeeds. When a wait() method is called, the thread releases the lock and enters the WaitSet. Wait until another thread calls notify or notifyAll to try to acquire the lock. Once the lock is used, threads in the EntrySet collection are notified to try to acquire the lock.

The resources

www.cnblogs.com/freelancy/p…

blog.csdn.net/qq_43783527/article/details/114669174

www.cnblogs.com/hongdada/p/…

Judge right and wrong from yourself, praise to listen to others, gain and loss in the number.

Collection of articles: gitee.com/mydb/interv…