根据校长视频学习,自己分析了一遍,供自己记录学习。
1 AQS引入
AQS是队列同步器,是提供同步锁的一种模板框架,也是lock锁实现的底层机制。
1.2 AQS执行流程
Aqs 是通过int 变量state来表示加锁状态,通过fifo同步队列来管理线程同步状态。流程:当前线程获取同步状态失败时,同步器会将线程以及等待信息构造成一个节点,加入同步队列中,同时阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,再次尝试获取同步状态。
AQS是经典采用了模板方法设计模式的,主要提供了一下五个魔版方法供我们重写加锁/解锁逻辑。
2 源码解读
以下源码基于非公平锁进行解析
同步队列器node状态描述:
2.1 lock
lock方法表示非阻塞式加锁,一起来看看是怎样实现的吧
final void lock() {
/**
* 对state通过cas的方式进行加锁
*/
if (compareAndSetState(0, 1))
/**
* 加锁成功设置当前拥有独占访问权限的线程
*/
setExclusiveOwnerThread(Thread.currentThread());
else
/** 加锁失败 设置尾节点**/
acquire(1);
}
accquire 表示以独占模式获取锁,忽略中断。通过调用至少一次 tryAcquire 来实现,成功返回。
public final void acquire(int arg) {
/**
* !tryAcquire(arg)表示加锁失败, addWaiter(Node.EXCLUSIVE), arg):表示将该线程加入到同步队列的尾节点
acquireQueued():将队列中的线程设置为等待唤醒状态
*/
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryquire()方法逻辑:使用cas修改state
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
/**
表示可重入
*/
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
addWaiter(Node.EXCLUSIVE) 逻辑:为当前线程和给定模式创建和排队节点
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
// 将当前线程插入到尾节点
Node pred = tail;
if (pred != null) {
node.prev = pred;
// cas 插入
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 插入失败则进行 死循环 自旋的方式 一直尝试cas插入。
enq(node);
return node;
}
acquireQueued方法逻辑:以独占不间断模式获取已在队列中的线程。由条件等待方法和获取使用。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
// 前节点为head表示可以竞争锁
if (p == head && tryAcquire(arg)) {
// 竞争成功设置当前节点为head
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
/**
shouldParkAfterFailedAcquire:将前节点设置为等待状态
parkAndCheckInterrupt():调用park 阻塞当前线程,并设置当前中断状态;ps:该线程由前节点线程负责唤醒
*/
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
// 发生异常:将当前节点移除队列并设置状态为cancel
cancelAcquire(node);
}
}
lock 总结:
2.2 tryLock 方法
trylock方法表示:非阻塞式获取锁,获取锁失败并不会进入阻塞(减少了用户态到内核态的调用)
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
nonfairTryAcquire(1);
// 逻辑比较简单就是cas尝试获取,获取失败则直接退出了而不会在加入到同步队列了
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//可重入
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
2.2 tryLock(arg )可超时获取锁
trylock(arg):在规定时间内尝试获取锁,超时后返回false,通过加入队列后判断时间,设置好超时park 就可以。时间一到就可以
底层调用了 doAcquireNanos 方法。
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
// 获取超时时间
final long deadline = System.nanoTime() + nanosTimeout;
// 加入同步队列
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
// 超时阻塞
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
总结:
2.3 unLock释放锁
底层调用了 aqs的 release方法
public final boolean release(int arg) {
//tryrelease 进行修改state变量 解锁
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
// 唤醒后继节点线程
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease:对锁状态进行修改
protected final boolean tryRelease(int releases) {
// 获取锁当前状态
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
// 设置当前独享线程为null
setExclusiveOwnerThread(null);
}
// 设置锁当前状态
setState(c);
return free;
}
unparkSuccessor:唤醒后继节点
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 获取后继节点
Node s = node.next;
// 后继节点是否有效
if (s == null || s.waitStatus > 0) {
s = null;
// 找到其中有效的节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
// 唤醒
LockSupport.unpark(s.thread);
}