如果ThreadA的锁还没有释放的情况下,ThreadB和ThreadC来争抢锁肯定是会失败,那么失败以后会调用shouldParkAfterFailedAcquire方法
Node有5中状态,分别是:CANCELLED(1),SIGNAL(-1)、CONDITION(-2)、PROPAGATE(-3)、默认状态(0)
CANCELLED: 在同步队列中等待的线程等待超时或被中断,需要从同步队列中取消该Node的结点, 其结点的waitStatus为CANCELLED,即结束状态,进入该状态后的结点将不会再变化
SIGNAL: 只要前置节点释放锁,就会通知标识为SIGNAL状态的后续节点的线程
CONDITION: 和Condition有关系,后续会讲解
PROPAGATE:共享模式下,PROPAGATE状态的线程处于可运行状态
0:初始状态
这个方法的主要作用是,通过Node的状态来判断,ThreadA竞争锁失败以后是否应该被挂起。
1. 如果ThreadA的pred节点状态为SIGNAL,那就表示可以放心挂起当前线程
2. 通过循环扫描链表把CANCELLED状态的节点移除
3. 修改pred节点的状态为SIGNAL,返回false.
返回false时,也就是不需要挂起,返回true,则需要调用parkAndCheckInterrupt挂起当前线程
private static boolean
shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;//前置节点的
waitStatus
if (ws == Node.SIGNAL)//如果前置节点为SIGNAL,意味着只需要等待其他前置节点的线程被释放,
return true;//返回true,意味着可以直接放心的挂起了
if (ws > 0) {//ws大于0,意味着prev节点取消了排队,直接移除这个节点就行
do {
node.prev = pred = pred.prev;
//相当于: pred=pred.prev;
node.prev=pred;
} while (pred.waitStatus > 0); //这里采用循环,从双向列表中移除CANCELLED的节点
pred.next = node;
} else {//利用cas设置prev节点的状态为SIGNAL(-1)
compareAndSetWaitStatus(pred, ws,
Node.SIGNAL);
}
return false;
}