|
Build 1.0_r1(from source) | |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
java.lang.Objectjava.util.concurrent.locks.AbstractQueuedSynchronizer.Node
static final class AbstractQueuedSynchronizer.Node
Wait queue node class.
The wait queue is a variant of a "CLH" (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks. We instead use them for blocking synchronizers, but use the same basic tactic of holding some of the control information about a thread in the predecessor of its node. A "status" field in each node keeps track of whether a thread should block. A node is signalled when its predecessor releases. Each node of the queue otherwise serves as a specific-notification-style monitor holding a single waiting thread. The status field does NOT control whether threads are granted locks etc though. A thread may try to acquire if it is first in the queue. But being first does not guarantee success; it only gives the right to contend. So the currently released contender thread may need to rewait.
To enqueue into a CLH lock, you atomically splice it in as new tail. To dequeue, you just set the head field.
+------+ prev +-----+ +-----+
head | | <---- | | <---- | | tail
+------+ +-----+ +-----+
Insertion into a CLH queue requires only a single atomic operation on "tail", so there is a simple atomic point of demarcation from unqueued to queued. Similarly, dequeing involves only updating the "head". However, it takes a bit more work for nodes to determine who their successors are, in part to deal with possible cancellation due to timeouts and interrupts.
The "prev" links (not used in original CLH locks), are mainly needed to handle cancellation. If a node is cancelled, its successor is (normally) relinked to a non-cancelled predecessor. For explanation of similar mechanics in the case of spin locks, see the papers by Scott and Scherer at http://www.cs.rochester.edu/u/scott/synchronization/
We also use "next" links to implement blocking mechanics. The thread id for each node is kept in its own node, so a predecessor signals the next node to wake up by traversing next link to determine which thread it is. Determination of successor must avoid races with newly queued nodes to set the "next" fields of their predecessors. This is solved when necessary by checking backwards from the atomically updated "tail" when a node's successor appears to be null. (Or, said differently, the next-links are an optimization so that we don't usually need a backward scan.)
Cancellation introduces some conservatism to the basic algorithms. Since we must poll for cancellation of other nodes, we can miss noticing whether a cancelled node is ahead or behind us. This is dealt with by always unparking successors upon cancellation, allowing them to stabilize on a new predecessor.
CLH queues need a dummy header node to get started. But we don't create them on construction, because it would be wasted effort if there is never contention. Instead, the node is constructed and head and tail pointers are set upon first contention.
Threads waiting on Conditions use the same nodes, but use an additional link. Conditions only need to link nodes in simple (non-concurrent) linked queues because they are only accessed when exclusively held. Upon await, a node is inserted into a condition queue. Upon signal, the node is transferred to the main queue. A special value of status field is used to mark which queue a node is on.
Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill Scherer and Michael Scott, along with members of JSR-166 expert group, for helpful ideas, discussions, and critiques on the design of this class.
| Field Summary | |
|---|---|
(package private) static int |
CANCELLED
waitStatus value to indicate thread has cancelled |
(package private) static int |
CONDITION
waitStatus value to indicate thread is waiting on condition |
(package private) static AbstractQueuedSynchronizer.Node |
EXCLUSIVE
Marker to indicate a node is waiting in exclusive mode |
(package private) AbstractQueuedSynchronizer.Node |
next
Link to the successor node that the current node/thread unparks upon release. |
(package private) AbstractQueuedSynchronizer.Node |
nextWaiter
Link to next node waiting on condition, or the special value SHARED. |
(package private) AbstractQueuedSynchronizer.Node |
prev
Link to predecessor node that current node/thread relies on for checking waitStatus. |
(package private) static AbstractQueuedSynchronizer.Node |
SHARED
Marker to indicate a node is waiting in shared mode |
(package private) static int |
SIGNAL
waitStatus value to indicate thread needs unparking |
(package private) Thread |
thread
The thread that enqueued this node. |
(package private) int |
waitStatus
Status field, taking on only the values: SIGNAL: The successor of this node is (or will soon be) blocked (via park), so the current node must unpark its successor when it releases or cancels. |
| Constructor Summary | |
|---|---|
AbstractQueuedSynchronizer.Node()
|
|
AbstractQueuedSynchronizer.Node(Thread thread,
AbstractQueuedSynchronizer.Node mode)
|
|
AbstractQueuedSynchronizer.Node(Thread thread,
int waitStatus)
|
|
| Method Summary | |
|---|---|
(package private) boolean |
isShared()
Returns true if node is waiting in shared mode |
(package private) AbstractQueuedSynchronizer.Node |
predecessor()
Returns previous node, or throws NullPointerException if null. |
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Field Detail |
|---|
static final int CANCELLED
static final int SIGNAL
static final int CONDITION
static final AbstractQueuedSynchronizer.Node SHARED
static final AbstractQueuedSynchronizer.Node EXCLUSIVE
volatile int waitStatus
volatile AbstractQueuedSynchronizer.Node prev
volatile AbstractQueuedSynchronizer.Node next
volatile Thread thread
AbstractQueuedSynchronizer.Node nextWaiter
| Constructor Detail |
|---|
AbstractQueuedSynchronizer.Node()
AbstractQueuedSynchronizer.Node(Thread thread,
AbstractQueuedSynchronizer.Node mode)
AbstractQueuedSynchronizer.Node(Thread thread,
int waitStatus)
| Method Detail |
|---|
final boolean isShared()
final AbstractQueuedSynchronizer.Node predecessor()
throws NullPointerException
NullPointerException
|
Build 1.0_r1(from source) | |||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||