synchronized achieve the realization of the principle of principle --- Moniter

Previous implementation principle of synchronized referred to moniter, did not introduce it.

Whether synchronization method or synchronized block, whether it is ACC_SYNCHRONIZEDor monitorenter, monitorexitare based on the Monitorrealization, then what is to introduce at this Monitor .

Operating system the tube

If you studied at the University of the operating system, you may remember the tube (monitors) is very important concept in the operating system. Similarly Monitor in java synchronization mechanisms are also used.

The tube (English: Monitors, also referred to as a monitor) is a program structure, a plurality of subprograms multiple worker threads (modules or objects) within the structure formed by mutually exclusive access to shared resources. These shared resources are generally a hardware device or a group of variables. The tube realized at one point in time, at most only one thread executing a subroutine of the tube. Compared with those of a concurrent program implemented mutually exclusive access to data by modifying the structure design, the tube to achieve greatly simplifies programming. The tube provides a mechanism, a thread can temporarily give up exclusive access, wait for certain conditions are met, to regain the implementation of the right to recover its exclusive access.

Java thread synchronization related Moniter

When multiple threads access to shared resources, often bring visibility and atomic safety issues. In order to solve this kind of thread safety issues, Java provides synchronization mechanism, mutex lock mechanism that ensures that resources at the same time only one thread can access the share. This mechanism of protection from surveillance lock Monitor, each object has its own monitoring lock Monitor.

First give an example, then we in the source code. We can monitor understood to include a special room of the building, this particular room the same time, only one guest (thread). The room contains a number of data and code.

If a customer wants to enter this particular room, he first needs to wait in line in the hallway (Entry Set). The scheduler will be based on certain criteria (such as FIFO) queue to select a client enters the room. If, for some reason, the client clients temporarily because of other things that they can not escape (thread is suspended), then he will be sent in addition to a special room to wait (Wait Set), this room can be a little after re-entering on that particular room. As mentioned above, the building house a total of three places.

In short, the monitor is used to monitor the thread enters a special room. His duty is to ensure that (same time) only one thread can access the data and code protected.

Monitor is a kind of synchronization tool can also be said to be a synchronization mechanism, it is often described as a target, the main features are:

All methods of an object are "mutually exclusive" of execution. Monitor only one run like a "license", as a thread enters any one of the methods required to obtain this "permission" to leave the license returned.

Usually provide singal mechanism: allows positive hold "permission" to temporarily give up the threads "permission", waiting for a true predicate (condition variable), and the condition is satisfied, the current process may "inform" the thread is waiting for the condition variable, so that he could run again to get permission.

Achieve Monitor

In the Java Virtual Machine (HotSpot) in, Monitor is based on the C ++ implementation by the ObjectMonitor achieve its primary 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 ;
  }

ObjectMonitor There are several key attributes:

_owner: pointing to an object thread holds ObjectMonitor

_WaitSet: store thread queue in wait state

_EntryList: stored in a waiting queue of threads that lock block

_recursions: the number of re-entry lock

_count: used to record the number of times the thread to acquire a lock

When multiple threads access synchronization code section will first enter the _EntryListqueue, a thread obtained when the object enters the monitor _Ownerarea and to monitor the _ownervariable is set to the current thread, and monitor the counter _countis incremented. That obtain the object lock.

If the holding monitor thread calls wait()the method, it will release the currently held monitor, _ownervariable recovery is null, _countfrom minus 1, while the thread into the _WaitSetcollection waiting to be awakened. If the current thread is finished will release the monitor (lock) and resets the value of the variable, so that other threads get into the monitor (lock). As shown below:

ObjectMonitor class provides several methods:

Get lock

void ATTR ObjectMonitor::enter(TRAPS) {
  Thread * const Self = THREAD ;
  void * cur ;
  //通过CAS尝试把monitor的`_owner`字段设置为当前线程
  cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
  //获取锁失败
  if (cur == NULL) {         assert (_recursions == 0   , "invariant") ;
     assert (_owner      == Self, "invariant") ;
     // CONSIDER: set or assert OwnerIsThread == 1
     return ;
  }
  // 如果旧值和当前线程一样,说明当前线程已经持有锁,此次为重入,_recursions自增,并获得锁。
  if (cur == Self) { 
     // TODO-FIXME: check for integer overflow!  BUGID 6557169.
     _recursions ++ ;
     return ;
  }

  // 如果当前线程是第一次进入该monitor,设置_recursions为1,_owner为当前线程
  if (Self->is_lock_owned ((address)cur)) { 
    assert (_recursions == 0, "internal state error");
    _recursions = 1 ;
    // Commute owner from a thread-specific on-stack BasicLockObject address to
    // a full-fledged "Thread *".
    _owner = Self ;
    OwnerIsThread = 1 ;
    return ;
  }

  // 省略部分代码。
  // 通过自旋执行ObjectMonitor::EnterI方法等待锁的释放
  for (;;) {
  jt->set_suspend_equivalent();
  // cleared by handle_special_suspend_equivalent_condition()
  // or java_suspend_self()

  EnterI (THREAD) ;

  if (!ExitSuspendEquivalent(jt)) break ;

  //
  // We have acquired the contended monitor, but while we were
  // waiting another thread suspended us. We don't want to enter
  // the monitor while suspended because that would surprise the
  // thread that suspended us.
  //
      _recursions = 0 ;
  _succ = NULL ;
  exit (Self) ;

  jt->java_suspend_self();
}
}

Release the lock

void ATTR ObjectMonitor::exit(TRAPS) {
   Thread * Self = THREAD ;
   //如果当前线程不是Monitor的所有者
   if (THREAD != _owner) { 
     if (THREAD->is_lock_owned((address) _owner)) { // 
       // Transmute _owner from a BasicLock pointer to a Thread address.
       // We don't need to hold _mutex for this transition.
       // Non-null to Non-null is safe as long as all readers can
       // tolerate either flavor.
       assert (_recursions == 0, "invariant") ;
       _owner = THREAD ;
       _recursions = 0 ;
       OwnerIsThread = 1 ;
     } else {
       // NOTE: we need to handle unbalanced monitor enter/exit
       // in native code by throwing an exception.
       // TODO: Throw an IllegalMonitorStateException ?
       TEVENT (Exit - Throw IMSX) ;
       assert(false, "Non-balanced monitor enter/exit!");
       if (false) {
          THROW(vmSymbols::java_lang_IllegalMonitorStateException());
       }
       return;
     }
   }
    // 如果_recursions次数不为0.自减
   if (_recursions != 0) {
     _recursions--;        // this is simple recursive enter
     TEVENT (Inflated exit - recursive) ;
     return ;
   }

   //省略部分代码,根据不同的策略(由QMode指定),从cxq或EntryList中获取头节点,通过ObjectMonitor::ExitEpilog方法唤醒该节点封装的线程,唤醒操作最终由unpark完成。

 

In addition to enter and exit methods, objectMonitor.cpp there

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

And other methods.

to sum up

Described above is the HotSpot virtual machine Moniter of the locking and unlocking of principle.

Through this article we know the sychronizedlock when the calls objectMonitor entermethod to unlock when invoked exitmethod. In fact, only before JDK1.6, synchronizedimplementation will directly call the ObjectMonitor enterand exitthis lock is called heavyweight lock. Why such a manner heavy lock it?

Java threads are mapped to the top of the operating system native threads, or if you want to wake up a blocked thread will need the help of the operating system, which is converted from user mode to kernel mode, and therefore the state transition takes a lot of processor time, for simple sync blocks of code (as synchronizedmodified get or setmethod) consumption state transition time may be longer than the execution time of the user codes, so that synchronizedis a java language heavyweight manipulation.

Therefore, the lock appears in the JDK1.6 done a lot of optimization, then there Lightweight lock, tend to lock, the lock cancellation, adaptive spin locks, lock coarsening (spin lock 1.4, there is only the default is closed, jdk1.6 are enabled by default), these operations are more efficient in order to share data between threads, to resolve competition issues.

优质文章参考:[1]  从jvm源码看synchronized

                         [2] 深入理解Java并发之synchronized实现原理

                         [3] 深入分析synchronized的实现原理

 

原文地址:https://www.hollischuang.com/archives/2030

Guess you like

Origin blog.csdn.net/weixin_44961794/article/details/90417336