[In-depth understanding of multithreading] The implementation principle of Monitor (4)

In -depth understanding of multithreading (1) - the implementation principle of Synchronized introduced Synchronizethe implementation principle, whether it is a synchronization method or a synchronization code block, whether it is or ACC_SYNCHRONIZEDis based on implementation, then this article will introduce what is Monitor .monitorentermonitorexitMonitor

monitor in operating system

If you studied operating systems in college, you probably remember that monitors are an important concept in operating systems. The same Monitor is also used in the java synchronization mechanism.

A monitor (English: Monitors, also known as a monitor) is a program structure in which multiple worker threads formed by multiple subprograms (objects or modules) in the structure mutually exclusive access to shared resources. These shared resources are generally hardware devices or a group of variables. The monitor implements that at most one thread is executing a subroutine of the monitor at a point in time. Monitor implementations greatly simplify programming compared to concurrent programming where mutually exclusive access is achieved by modifying data structures. The monitor provides a mechanism whereby a thread can temporarily give up exclusive access, wait for certain conditions to be met, and regain execution rights to restore its exclusive access.

Java thread synchronization related Monitor

When multiple threads access shared resources, security issues of visibility and atomicity often arise. In order to solve this kind of thread safety problem, Java provides a synchronization mechanism and a mutual exclusion lock mechanism, which ensures that only one thread can access shared resources at the same time. The guarantee of this mechanism comes from the monitoring lock Monitor, and each object has its own monitoring lock Monitor.

Let's take an example first, and then we will go to the source code. We can think of a monitor as a building that contains a special room that can only have one guest (thread) at a time. This room contains some data and code.


If a customer wants to enter this special room, he first needs to wait in line in the corridor (Entry Set). The scheduler will choose queued customers to enter the room based on some criterion (such as FIFO). If, for some reason, the client client can't get away temporarily because of other things (the thread is suspended), then he will be sent to another room (Wait Set) dedicated to waiting, which can be used for a while. Then enter that special room again. As mentioned above, there are three places in this building.


In short, a monitor is one used to monitor the entry of these threads into a particular room. His obligation is to ensure that only one thread (at the same time) can access the protected data and code.

Monitor is actually a synchronization tool, or a synchronization mechanism. It is usually described as an object. The main features are:

All methods of the object are executed "mutually". For example, a Monitor has only one running "permission". Any thread entering any method needs to obtain this "permission", and the permission is returned when it leaves.

Usually a singal mechanism is provided: the thread that is holding the "permit" is allowed to temporarily give up the "permission", waiting for a predicate to become true (condition variable), and when the condition is satisfied, the current process can "notify" the thread that is waiting for this condition variable, so that he can go back to get permission to run.

Implementation of the monitor

In the Java virtual machine (HotSpot), Monitor is implemented based on C++ and implemented by ObjectMonitor. Its main data structure is as follows:

  ObjectMonitor() {
    _header       = NULL;
    _count        = 0;
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL;
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

Source address: objectMonitor.hpp

There are several key properties in ObjectMonitor:

_owner: points to the thread holding the ObjectMonitor object

_WaitSet: Stores the thread queue in the wait state

_EntryList: Stores the thread queue waiting for the lock block state

_recursions: the number of times the lock is reentrant

_count: used to record the number of times the thread acquired the lock

When multiple threads access a piece of synchronous code at the same time, they will first enter the _EntryListqueue. When a thread obtains the monitor of the object, it enters the _Ownerarea and sets the _ownervariable in the monitor to the current thread, and the counter in the monitor is incremented _countby 1. That is, the object lock is acquired.

If the thread holding the monitor calls the wait()method, the currently held monitor will be released, the _ownervariable will be restored to null, _countdecremented by 1, and the thread will enter the _WaitSetcollection and wait to be woken up. If the current thread finishes executing, it will also release the monitor (lock) and reset the value of the variable, so that other threads can enter and acquire the monitor (lock). As shown below


Several methods are provided in the ObjectMonitor class:

acquire lock





release lock




In addition to the enter and exit methods, objectMonitor.cpp also has

void      wait(jlong millis, bool interruptable, TRAPS);
void      notify(TRAPS);
void      notifyAll(TRAPS);

and other methods.

Summarize

The above is the principle of locking and unlocking of Monitor in HotSpot virtual machine.

Through this article, we know that sychronizedthe method of objectMonitor will be called when locking, and the entermethod will be called when unlocking exit. In fact, only before JDK1.6, synchronizedthe implementation will directly call the entersum of ObjectMonitor exit, this kind of lock is called heavyweight lock . Why is it so heavy to operate the lock in this way?

  • Java threads are mapped to the native threads of the operating system. If you want to block or wake up a thread, you need the help of the operating system. This requires the conversion from user mode to core mode, so the state transition takes a lot of processor time. For simple synchronized blocks of code (such as synchronizedmodified get or setmethods), state transitions may take longer than user code execution, so it synchronizedis a heavyweight operation in the Java language.

Therefore, in JDK1.6, a lot of optimizations have been made to locks, and then there are lightweight locks , biased locks , lock elimination , and adaptive spin locks . , and lock coarsening (spin locks are only the default in 1.4). is turned off, jdk1.6 is turned on by default), these operations are to share data more efficiently between threads and solve the problem of competition. Later articles will continue to introduce these types of locks and the relationship between them.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325439435&siteId=291194637