ObjectMonitor,ObjectWaiter 實現wait(),notify()


0、java對象鎖監視器

在JVM的規范中,有這么一些話:
“在JVM中,每個對象和類在邏輯上都是和一個監視器相關聯的”
“為了實現監視器的排他性監視能力,JVM為每一個對象和類都關聯一個鎖”
鎖住了一個對象,就是獲得對象相關聯的監視器

 

監視器好比一做建築,它有一個很特別的房間,房間里有一些數據,而且在同一時間只能被一個線程占據,

進入這個建築叫做"進入監視器"

進入建築中的那個特別的房間叫做"獲得監視器"

占據房間叫做"持有監視器"

離開房間叫做"釋放監視器"

離開建築叫做"退出監視器".
而一個鎖就像一種任何時候只允許一個線程擁有的特權.
一個線程可以允許多次對同一對象上鎖.對於每一個對象來說,java虛擬機維護一個計數器,記錄對象被加了多少次鎖,沒被鎖的對象的計數器是0,線程每加鎖一次,計數器就加1,每釋放一次,計數器就減1.當計數器跳到0的時候,鎖就被完全釋放了.

java虛擬機中的一個線程在它到達監視區域開始處的時候請求一個鎖.JAVA程序中每一個監視區域都和一個對象引用相關聯

監視器:monitor
鎖:lock(JVM里只有一種獨占方式的lock)
進入監視器:monitorenter
離開/釋放監視器:monitorexit
(monitorentermonitorexit是JVM的指令)
擁有者:owner

在JVM里,monitor就是實現lock的方式。
monitorenter就是獲得某個對象的lock(owner是當前線程)
monitorexit就是釋放某個對象的lock

 


 

 

在oracle JVM 1.6 里面實現的object的wait 和notify方法是在synchronizer.cpp里實現。 

先介紹2個對象:

一. ObjectMonitor  對象 主要用來監視創立的Object 

在synchronizer.cpp 里定義了,ObjectMonitor 的對象,我們來看ObjectMonitor的對象的結構體

ObjectMonitor::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 ;
}

每個object的對象里 markOop->monitor() 里可以保存ObjectMonitor的對象。

 

建立ObjectMonitor的算法:

如果不存在,可以向Thread 的ObjectMonitor 的對象列表中Allocate free objectMonitor 對象。 

每個線程都有ObjectMonitor 的free和used的objectMonitor對象列表,如果沒有free objectMonitor對象列表,將向global 中ListLock Allocate為了提高效率。

 

二.  ObjectWaiter 對象

 ObjectWaiter 對象

class ObjectWaiter : public StackObj {
 public:
  enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
  enum Sorted  { PREPEND, APPEND, SORTED } ;
  ObjectWaiter * volatile _next;
  ObjectWaiter * volatile _prev;
  Thread*       _thread;
  ParkEvent *   _event;
  volatile int  _notified ;
  volatile TStates TState ;
  Sorted        _Sorted ;           // List placement disposition
  bool          _active ;           // Contention monitoring is enabled
 public:
  ObjectWaiter(Thread* thread) {
    _next     = NULL;
    _prev     = NULL;
    _notified = 0;
    TState    = TS_RUN ;
    _thread   = thread;
    _event    = thread->_ParkEvent ;
    _active   = false;
    assert (_event != NULL, "invariant") ;
  }
  void wait_reenter_begin(ObjectMonitor *mon) {
    JavaThread *jt = (JavaThread *)this->_thread;
    _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
  }
  void wait_reenter_end(ObjectMonitor *mon) {
    JavaThread *jt = (JavaThread *)this->_thread;
    JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
  }
};

 

ObjectWaiter 對象里存放thread(線程對象) 和 ParkEvent(線程的unpark), 每一個等待鎖的線程都會有一個ObjectWaiter對象.

而objectwaiter是個雙向鏈表結構的對象。

 

我們可以看到在ObjectMonitor對象里有2個隊列成員_WaitSet 和 _EntryList 存放的就是ObjectWaiter

_WaitSet:

主要存放所有wait的線程的對象,也就是說如果有線程處於wait狀態,將被掛入這個隊列

_EntryList:

所有在等待獲取鎖的線程的對象,也就是說如果有線程處於等待獲取鎖的狀態的時候,將被掛入這個隊列。

 

三、Wait 方法實現:

ObjectSynchronizer::wait方法

通過object的對象中找到ObjectMonitor對象

調用方法 

void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)

通過ObjectMonitor::AddWaiter調用把新建立的ObjectWaiter對象放入到 _WaitSet 的隊列的末尾中

然后在ObjectMonitor::exit釋放鎖,接着 thread_ParkEvent->park  也就是wait

 

 

四、Notify方法的實現:

ObjectSynchronizer::notify方法

調用ObjectSynchronizer::inflate

object的對象中找到ObjectMonitor對象 

 

然后調用方法ObjectMonitor::notify

調用ObjectMonitor::DequeueWaiter 摘除第一個ObjectWaiter對象從_WaitSet 的隊列中

並把這個ObjectWaiter對象放入_EntryList中,_EntryList 存放的是ObjectWaiter的對象列表,列表的大小就是那些所有在等待這個對象鎖的線程數。

注意這里並沒有調用ObjectMonitor::exit釋放鎖

 

NotifyALL和Notify 的區別就是

通過遍歷調用ObjectMonitor::DequeueWaiter,把所有的_WaitSet的隊列中的ObjectWaiter對象放入到_EntryList中

關於放入到_EntryList的策略大概有4中Policy,其中還涉及到一個_cxq的隊列,先不具體介紹了

notify, 和notifyAll 都沒有釋放對象的鎖,而是在Synchronizer同步塊結束的時候釋放

 

如何釋放鎖

調用ObjectMonitor::exit

從_EntryList里找到一個ObjectWaiter,因為ObjectWaiter里有線程的_event ParkEvent,調用unpark() 通知ObjectWaite里的線程運行(拿到鎖),具體實現在ObjectMonitor::ExitEpilog方法里

 

 

 Reference

java 中的 wait 和 notify 實現的源碼分析

 http://bbs.csdn.net/topics/80052746


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM