ReentrantLock源码
大纲
AQS结构
非公平锁nonfairTryAcquires实现
公平锁TryAcquires实现
获取锁失败,将线程添加到链表:addWaiter
队列为空或CAS修改链表尾节点失败,将当前节点设置为尾节点
尝试再次获取锁,未获取到锁则挂起当前节点线程
java
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {//死循环
final Node p = node.predecessor();//获得该node的前置节点
/**
* 如果前置节点是head,表示之前的节点就是正在运行的线程,表示是第一个排队的
(一般讲队列中第一个是正在处理的,可以想象买票的过程,第一个人是正在买票(处理中),第二个才是真正排队的人);
那么再去tryAcquire尝试获取锁,如果获取成功,说明此时前置线程已经运行结束,则将head设置为当前节点返回
*
*
**/
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC,将前置节点移出队列,这样就没有指针指向它,可以被gc回收
failed = false;
return interrupted;//返回false表示不能被打断,意思是没有被挂起,也就是获得到了锁
}
/**shouldParkAfterFailedAcquire将前置node设置为需要被挂起,
注意这里的waitStatus是针对当前节点来说的,
即是前置node的ws指的是下一个节点的状态**/
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())//挂起线程 park()
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);//如果失败取消尝试获取锁(从上面的代码看只有进入p == head && tryAcquire(arg)这个逻辑是才会触发,这个时候前置节点正好在当前节点入队的时候执行完,当前节点正好获得锁,具体的代码以后分析)
}
}
//看到因为是死循环,所以当执行到parkAndCheckInterrupt()时,当前线程被挂起,等到某一天被unpark继续执行,这个时候已经是对头的第二个节点了,那么就会进入if (p == head && tryAcquire(arg))逻辑获取到锁并结束循环