AQS-ReentrantLock(加锁)源码浅析
1、ReentrantLock
ReentrantLock实现主要依赖extends AbstractQueuedSynchronizer,在源码里面xxxSync extends Sync实现lock 方法,而Sync 父类即是AbstractQueuedSynchronizer。
实现方法如下:通过acquire(1);方法内部实现 AQS。
final void lock() {
acquire(1);
}
2、acquire 方法
(1)tryAcquire(arg),尝试获取资源,是否获取成功获取成功,直接放行继续执行。否则执行acquireQueued。
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
3、acquireQueued方法
(1)将尝试获取资源失败的 线程,创建链表节点进入阻塞队列。
(2)addWaiter,添加并创建节点,Node.EXCLUSIVE 默认独占模式,NODE.SHARED 共享模式。
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
//获取链表尾部节点
Node pred = tail;
//尾部节点不为空,将当前节点指向 尾部节点,作为新的尾部节点
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}}
//如果尾部节点 是 null,enq进行初始化节点,并cas 将当前创建新节点设置到链表尾部节点。
enq(node);
//返回当前节点
return node;
}
(3)回到acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
//尝试是否失败
boolean failed = true;
try {
//是否被打断
boolean interrupted = false;
//注意这里将不断循环重试如下操作
for (;;) {
//获取当前节点的前节点
final Node p = node.predecessor();
//如果当前节点的 前节点==head节点,那么当前节点即可尝试去获取资源,如果获取资源成功,表示当前节点的前节点已经无效,将当前节点设置为 head节点,将前节点置为null帮助GC回收。返回尝试获取状态,以及是否被打断。
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//如果当前节点不是 head节点 or 尝试获取资源失败。
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true;
}} finally {
//如果响应中断,异常表示当前节点,被取消
if (failed)
cancelAcquire(node);
}}
(4)shouldParkAfterFailedAcquire,循环检测是否能够进行unpark阻塞状态,等待许可。
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//获取前节点的 节点状态,(SIGNAL:指示后续线程,需要许可解锁阻塞)
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//前节点 状态 ==SIGNAL 返回true 由parkAndCheckInterrupt方法进行 park阻塞,暂停循环。
return true;
if (ws > 0) {
//前节点状态>0 (CANCELLED:表示线程已取消的waitStatus值),可能由于打断 or timeout结束了当前节点。
do {
//出现如上情况,当前节点会,不断循环往上查找到状态不是>0的节点,并把自己的前驱指向该节点。
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//如果前节点状态 !>0 and != Node.SIGNAL,表示当前节点处于其他两种状态(CONDITION、PROPAGATE),将通过cas将前节点状态设置为 Node.SIGNAL。
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;}
5、当从shouldParkAfterFailedAcquire方法获取park许可,接下来通过parkAndCheckInterrupt调用park进行阻塞,并返回当前线程是否被打断。
private final boolean parkAndCheckInterrupt() {
//阻塞等待 unpark许可,终止 for循环。
LockSupport.park(this);
return Thread.interrupted();
}
6、cancelAcquire 取消当前节点在链表。
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
Node predNext = pred.next;
node.waitStatus = Node.CANCELLED;
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
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 }}