doAcquireShared()方法
该方法在共享模式以不响应中断的方式阻塞等待获取锁,实现如下:
1、将当前线程封装成节点入队;
2、在死循环中调用park方法。第一次循环(自旋、acquire loop),或者被唤醒从park方法返回后,会判断前驱节点是否是头节点,以及调用tryAcquire()方法是否返回true,如果这2个条件都为真,由当前节点自己设置为头节点,并将后继节点唤醒,然后return;退出死循环。如果这2个条件不满足,会继续调用park方法阻塞等待。
3、在第二步中,被唤醒从park方法返回后,有一个额外操作就是会判断线程的中断状态,如果中断状态为true,仅仅是设置中断标志位interrupted,不抛出中断异常。
4、在第二步中,在判断那2个条件不满足,和调用park方法阻塞等待之间,还有一个操作就是判断在获取失败后是否应该调用park方法阻塞等待。即shouldParkAfterFailedAcquire方法。在acquire loop中会不断调用该方法retry,使该方法最终总是趋向于返回true。
/**
* Acquires in shared uninterruptible mode.
* @param arg the acquire argument
*/
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);//将当前线程封装成节点入队
boolean failed = true;
try {
boolean interrupted = false;
for (;;) { //死循环
final Node p = node.predecessor();
if (p == head) { //如果前驱节点是头节点
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r); //当前节点设置为头节点,并唤醒后继节点
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return; //退出死循环
}
}
if (shouldParkAfterFailedAcquire(p, node) && //获取失败后判断是否应该park阻塞等待
parkAndCheckInterrupt()) //调用park方法阻塞等待,park方法返回后判断是否中断
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
doAcquireSharedInterruptibly方法
该方法在共享模式以响应中断的方式阻塞获取锁。实现逻辑与doAcquireShared方法是基本相同的。不同的是在从park方法返回后,如果判断线程的中断状态为true,会抛出中断异常。
/**
* Acquires in shared interruptible mode.
* @param arg the acquire argument
*/
private void doAcquireSharedInterruptibly(int arg