/*** Creates and enqueues node for current thread and given mode.
*
*@parammode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
*@returnthe new node*/
privateNode addWaiter(Node mode) {
Node node= newNode(Thread.currentThread(), mode);//Try the fast path of enq; backup to full enq on failure
Node pred =tail;if (pred != null) {
node.prev=pred;if(compareAndSetTail(pred, node)) {
pred.next=node;returnnode;
}
}
enq(node);returnnode;
}/*** CAS tail field. Used only by enq.*/
private final booleancompareAndSetTail(Node expect, Node update) {return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}/*** Inserts node into queue, initializing if necessary. See picture above.
*@paramnode the node to insert
*@returnnode's predecessor*/
private Node enq(finalNode node) {for(;;) {
Node t=tail;if (t == null) { //Must initialize
if (compareAndSetHead(newNode()))
tail=head;
}else{
node.prev=t;if(compareAndSetTail(t, node)) {
t.next=node;returnt;
}
}
}
}/*** Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
*@parampred node's predecessor holding status
*@paramnode the node
*@return{@codetrue} if thread should block*/
private static booleanshouldParkAfterFailedAcquire(Node pred, Node node) {int ws =pred.waitStatus;if (ws ==Node.SIGNAL)/** This node has already set status asking a release
* to signal it, so it can safely park.*/
return true;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and
* indicate retry.*/
do{
node.prev= pred =pred.prev;
}while (pred.waitStatus > 0);
pred.next=node;
}else{/** waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}return false;
}/*** Convenience method to park and then check if interrupted
*
*@return{@codetrue} if interrupted*/
private final booleanparkAndCheckInterrupt() {
LockSupport.park(this);returnThread.interrupted();
}/*** Sets head of queue, and checks if successor may be waiting
* in shared mode, if so propagating if either propagate > 0 or
* PROPAGATE status was set.
*
*@paramnode the node
*@parampropagate the return value from a tryAcquireShared*/
private void setHeadAndPropagate(Node node, intpropagate) {
Node h= head; //Record old head for check below
setHead(node);/** Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus either before
* or after setHead) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.*/
if (propagate > 0 || h == null || h.waitStatus < 0 ||(h= head) == null || h.waitStatus < 0) {
Node s=node.next;if (s == null ||s.isShared())
doReleaseShared();
}
}/*** Release action for shared mode -- signals successor and ensures
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)*/
private voiddoReleaseShared() {/** Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.*/
for(;;) {
Node h=head;if (h != null && h !=tail) {int ws =h.waitStatus;if (ws ==Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue; //loop to recheck cases
unparkSuccessor(h);
}else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue; //loop on failed CAS
}if (h == head) //loop if head changed
break;
}
}/*** Cancels an ongoing attempt to acquire.
*
*@paramnode the node*/
private voidcancelAcquire(Node node) {//Ignore if node doesn't exist
if (node == null)return;
node.thread= null;//Skip cancelled predecessors
Node pred =node.prev;while (pred.waitStatus > 0)
node.prev= pred =pred.prev;//predNext is the apparent node to unsplice. CASes below will//fail if not, in which case, we lost race vs another cancel//or signal, so no further action is necessary.
Node predNext =pred.next;//Can use unconditional write instead of CAS here.//After this atomic step, other Nodes can skip past us.//Before, we are free of interference from other threads.
node.waitStatus =Node.CANCELLED;//If we are the tail, remove ourselves.
if (node == tail &&compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext,null);
}else{//If successor needs signal, try to set pred's next-link//so it will get one. Otherwise wake it up to propagate.
intws;if (pred != head &&((ws= pred.waitStatus) == Node.SIGNAL ||(ws<= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&pred.thread!= null) {
Node next=node.next;if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
}else{
unparkSuccessor(node);
}
node.next= node; //help GC
}
}