vm/runtime/objectMonitor.hpp 第61行,定义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.cpp 第186行,关于线程获取对象锁相关的一些说明备注内容,源码如下:
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 |