一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
简介
在Java并发体系中,AQS是一个运用非常广泛的工具类,它全称是AbstractQueuedSynchronizer(抽象队列同步器)。从它名字就可以感受到三个含义:
- 抽象的
它是一个抽象类,并不能直接使用在我们项目中。
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable
也正因为它是抽象的,它被灵活应用在各种JUX类上。
- 队列
它借助先进先出 (FIFO) 等待队列的实现相关的阻塞和同步。
- 同步器
它是为了实现同步的对象。
关键属性
- state 同步器状态,可以理解为当前同步器状态。不同实现类,它具有不同的意义,比如在
ReentrantLock
中,它可以代表锁的状态。1表示有锁,0表示锁。
相关操作:
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
// 原子操作,通过对象的CAS操作实现。
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
-
exclusiveOwnerThread 占有当前同步器的线程
-
head和tail,当前队列的队头元素和队尾元素。
结合实现类ReentrantLock理解AQS
加锁
ReentrantLock,是我们最常用的锁。它底层就是借助了AQS实现加锁和释放锁的过程。
加锁时可以分为两种情况:
-
锁未被占用,可以直接拿到。
-
锁已被占用,需要等待其他锁释放再获取。
对应ReentrantLock的非公平锁的源码
// 尝试占用税,如果占用成功,说明加锁成功
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
其中compareAndSetState
为AQS方法,它通过CAS,保证原子性。
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
情况1. 通过compareAndSetState(0, 1)方法,直接获得锁
为什么它返回true可以表示获取成功呢?因为它把AQS的state当成锁状态了,state = 0 表示未有线程获得锁;state = 1 表示线程获得锁。compareAndSetState(0, 1)返回true,说明它从未获锁状态,拿到锁了。
情况2. acquire(1),获得锁。
//AQS 方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
它的核心流程:尝试获得锁 -》 如果获取锁失败,则把加入到队列中,并将线程状态至为wait -》其他占锁线程,释放锁,并通知等待的节点。
源码比较复杂,总结的流程图如下所示:
释放锁
当前拿到的锁线程,释放锁,并唤醒队列的其他节点(线程)
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
流程图如下。