hotspot source code - object monitor

vm/runtime/objectMonitor.hpp61行,定义ObjectMonitor,源码如下:

616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
// WARNING://   This is a very sensitive and fragile class. DO NOT make any// change unless you are fully aware of the underlying semantics.//   This class can not inherit from any other class, because I have// to let the displaced header be the very first word. Otherwise I// have to let markOop include this file, which would export the// monitor data structure to everywhere.//// The ObjectMonitor class is used to implement JavaMonitors which have// transformed from the lightweight structure of the thread stack to a// heavy weight lock due to contention// It is also used as RawMonitor by the JVMTIclass ObjectMonitor { public:  enum {    OM_OK,                    // no error    OM_SYSTEM_ERROR,          // operating system error    OM_ILLEGAL_MONITOR_STATE, // IllegalMonitorStateException    OM_INTERRUPTED,           // Thread.interrupt()    OM_TIMED_OUT              // Object.wait() timed out  }; public:  // TODO-FIXME: the "offset" routines should return a type of off_t instead of int ...  // ByteSize would also be an appropriate type.  static int header_offset_in_bytes()      { return offset_of(ObjectMonitor, _header);     }  static int object_offset_in_bytes()      { return offset_of(ObjectMonitor, _object);     }  static int owner_offset_in_bytes()       { return offset_of(ObjectMonitor, _owner);      }  static int count_offset_in_bytes()       { return offset_of(ObjectMonitor, _count);      }  static int recursions_offset_in_bytes()  { return offset_of(ObjectMonitor, _recursions); }  static int cxq_offset_in_bytes()         { return offset_of(ObjectMonitor, _cxq) ;       }  static int succ_offset_in_bytes()        { return offset_of(ObjectMonitor, _succ) ;      }  static int EntryList_offset_in_bytes()   { return offset_of(ObjectMonitor, _EntryList);  }  static int FreeNext_offset_in_bytes()    { return offset_of(ObjectMonitor, FreeNext);    }  static int WaitSet_offset_in_bytes()     { return offset_of(ObjectMonitor, _WaitSet) ;   }  static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible);}  static int Spinner_offset_in_bytes()     { return offset_of(ObjectMonitor, _Spinner);    } public:  // Eventaully we'll make provisions for multiple callbacks, but  // now one will suffice.  static int (*SpinCallbackFunction)(intptr_t, int) ;  static intptr_t SpinCallbackArgument ; public:  markOop   header() const;  void      set_header(markOop hdr);

vm/runtime/objectMonitor.cpp186行,关于线程获取对象锁相关的一些说明备注内容,源码如下:

186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
// -----------------------------------------------------------------------------// Theory of operations -- Monitors lists, thread residency, etc://// * A thread acquires ownership of a monitor by successfully//   CAS()ing the _owner field from null to non-null.//// * Invariant: A thread appears on at most one monitor list --//   cxq, EntryList or WaitSet -- at any one time.//// * Contending threads "push" themselves onto the cxq with CAS//   and then spin/park.//// * After a contending thread eventually acquires the lock it must//   dequeue itself from either the EntryList or the cxq.//// * The exiting thread identifies and unparks an "heir presumptive"//   tentative successor thread on the EntryList.  Critically, the//   exiting thread doesn't unlink the successor thread from the EntryList.//   After having been unparked, the wakee will recontend for ownership of//   the monitor.   The successor (wakee) will either acquire the lock or//   re-park itself.////   Succession is provided for by a policy of competitive handoff.//   The exiting thread does _not_ grant or pass ownership to the//   successor thread.  (This is also referred to as "handoff" succession").//   Instead the exiting thread releases ownership and possibly wakes//   a successor, so the successor can (re)compete for ownership of the lock.//   If the EntryList is empty but the cxq is populated the exiting//   thread will drain the cxq into the EntryList.  It does so by//   by detaching the cxq (installing null with CAS) and folding//   the threads from the cxq into the EntryList.  The EntryList is//   doubly linked, while the cxq is singly linked because of the//   CAS-based "push" used to enqueue recently arrived threads (RATs).//// * Concurrency invariants:////   -- only the monitor owner may access or mutate the EntryList.//      The mutex property of the monitor itself protects the EntryList//      from concurrent interference.//   -- Only the monitor owner may detach the cxq.//// * The monitor entry list operations avoid locks, but strictly speaking//   they're not lock-free.  Enter is lock-free, exit is not.//   For a description of 'Methods and apparatus providing non-blocking access//   to a resource,' see U.S. Pat. No. 7844973.//// * The cxq can have multiple concurrent "pushers" but only one concurrent//   detaching thread.  This mechanism is immune from the ABA corruption.//   More precisely, the CAS-based "push" onto cxq is ABA-oblivious.//// * Taken together, the cxq and the EntryList constitute or form a//   single logical queue of threads stalled trying to acquire the lock.//   We use two distinct lists to improve the odds of a constant-time//   dequeue operation after acquisition (in the ::enter() epilog) and//   to reduce heat on the list ends.  (c.f. Michael Scott's "2Q" algorithm).//   A key desideratum is to minimize queue & monitor metadata manipulation//   that occurs while holding the monitor lock -- that is, we want to//   minimize monitor lock holds times.  Note that even a small amount of//   fixed spinning will greatly reduce the # of enqueue-dequeue operations//   on EntryList|cxq.  That is, spinning relieves contention on the "inner"//   locks and monitor metadata.////   Cxq points to the the set of Recently Arrived Threads attempting entry.//   Because we push threads onto _cxq with CAS, the RATs must take the form of//   a singly-linked LIFO.  We drain _cxq into EntryList  at unlock-time when//   the unlocking thread notices that EntryList is null but _cxq is != null.////   The EntryList is ordered by the prevailing queue discipline and//   can be organized in any convenient fashion, such as a doubly-linked list or//   a circular doubly-linked list.  Critically, we want insert and delete operations//   to operate in constant-time.  If we need a priority queue then something akin//   to Solaris' sleepq would work nicely.  Viz.,//   http://agg.eng/ws/on10_nightly/source/usr/src/uts/common/os/sleepq.c.//   Queue discipline is enforced at ::exit() time, when the unlocking thread//   drains the cxq into the EntryList, and orders or reorders the threads on the//   EntryList accordingly.////   Barring "lock barging", this mechanism provides fair cyclic ordering,//   somewhat similar to an elevator-scan.//// * The monitor synchronization subsystem avoids the use of native//   synchronization primitives except for the narrow platform-specific//   park-unpark abstraction.  See the comments in os_solaris.cpp regarding//   the semantics of park-unpark.  Put another way, this monitor implementation//   depends only on atomic operations and park-unpark.  The monitor subsystem//   manages all RUNNING->BLOCKED and BLOCKED->READY transitions while the//   underlying OS manages the READY<->RUN transitions.//// * Waiting threads reside on the WaitSet list -- wait() puts//   the caller onto the WaitSet.//// * notify() or notifyAll() simply transfers threads from the WaitSet to//   either the EntryList or cxq.  Subsequent exit() operations will//   unpark the notifyee.  Unparking a notifee in notify() is inefficient -//   it's likely the notifyee would simply impale itself on the lock held//   by the notifier.//// * An interesting alternative is to encode cxq as (List,LockByte) where//   the LockByte is 0 iff the monitor is owned.  _owner is simply an auxiliary//   variable, like _recursions, in the scheme.  The threads or Events that form//   the list would have to be aligned in 256-byte addresses.  A thread would//   try to acquire the lock or enqueue itself with CAS, but exiting threads//   could use a 1-0 protocol and simply STB to set the LockByte to 0.//   Note that is is *not* word-tearing, but it does presume that full-word//   CAS operations are coherent with intermix with STB operations.  That's true//   on most common processors.//// * See also http://blogs.sun.com/dave

References

  1. vm/runtime/objectMonitor.hpp
  2. vm/runtime/objectMonitor.cpp