AbstractQueuedSynchronizer基本概念
AQS
同步状态
private volatile int state;
//1
protected final int getState() {
return state;
}
//2
protected final void setState(int newState) {
state = newState;
}
//3
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
Node:
头节点的线程对象为空,头节点就是当前持有锁的线程
//Node的职责
//【准备唤醒下一个SIGNAL 准备退出CANCELLED 条件队列CONDITION PROPAGATE共享头节点】
volatile int waitStatus;
AQS 加锁 acquire
用户实现:获取锁成功或失败逻辑AQS实现:失败了构造节点,放入阻塞队列等待
public final void acquire(int arg) {
//1. tryAcquire由用户自己定义,取锁是成功还是失败
//2. 放入阻塞队列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
注:Lock
在ReentrantLock的lock方法中,tryAcquire()的实现就是使用CAS的方式获取锁,如果tryAcquire获取失败,则在acquireQueued()中会调用底层的LockSupport.park(),也就是操作系统的线程阻塞方法,这就是锁升级的过程
1 addWiter:把线程构建为节点,加入同步队列 (头节点是当前持有锁的线程)
2.acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
-
加入同步队列,之前在挣扎一下,有可能前一个线程结束了,所以先tryAcquire一下
-
如果获取失败,那么阻塞等待
- shouldParkAfterFailedAcquire 又给了一次机会抢锁
- parkAndCheckInterrupt调用 LockSupport.park(this) 阻塞
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//1. 获取锁之前必须前驱是头节点
if (p == head && tryAcquire(arg)) {
//获取锁成功,把他设置为头节点
setHead(node);
//之前的头节点出去
p.next = null; // help GC
failed = false;
return interrupted;
}
//获取锁失败的情况
//然后阻塞获取锁失败的线程
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
Lock如何实现不可响应中断
park()会响应中断,会使阻塞线程唤醒,不会抛出异常,唤醒就是重新acquireQueued()尝试是否能获取到锁
AQS 解锁 release
用户实现:获解锁成功或失败逻辑AQS实现:成功了唤醒后继节点(unparkSuccessor)- 先找头节点下一个
- 找不到从tail往前找
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
//只有后面没有节点,刚刚有节点加入,才唤醒(通过waitStatus来判断)
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}