AQS 框架
AQS 框架概览
首先,我们通过下面的架构图来整体了解一下

上图中有颜色的为


- 非公平锁:如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取;
- 公平锁:如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。
AQS 数据结构
先来看下

解释一下几个方法和属性值的含义:
方法和属性值 | 含义 |
---|---|
waitStatus | 当前节点在队列中的状态 |
thread | 表示处于该节点的线程 |
prev | 前驱指针 |
predecessor | 返回前驱节点,没有的话抛出 |
nextWaiter | 指向下一个处于 |
next | 后继指针 |
线程两种锁的模式:
模式 | 含义 |
---|---|
SHARED | 表示线程以共享的模式等待锁 |
EXCLUSIVE | 表示线程正在以独占的方式等待锁 |
枚举 | 含义 |
---|---|
0 | 当一个 |
CANCELLED | 为 |
CONDITION | 为 |
PROPAGATE | 为 |
SIGNAL | 为 |
同步状态State
在了解数据结构后,接下来了解一下
// java.util.concurrent.locks.AbstractQueuedSynchronizer
private volatile int state;
下面提供了几个访问这个字段的方法:
方法名 | 描述 |
---|---|
protected final int getState() | 获取 |
protected final void setState(int newState) | 设置 |
protected final boolean compareAndSetState(int expect, int update) | 使用 |
这几个方法都是

对于我们自定义的同步工具,需要自定义获取同步状态和释放状态的方式,也就是
同步器接口
从架构图中可以得知,
protected boolean isHeldExclusively() 该线程是否正在独占资源。只有用到Condition 才需要去实现它。protected boolean tryAcquire(int arg) 独占方式。arg 为获取锁的次数,尝试获取资源,成功则返回True ,失败则返回False 。protected boolean tryRelease(int arg) 独占方式。arg 为释放锁的次数,尝试释放资源,成功则返回True ,失败则返回False 。protected int tryAcquireShared(int arg) 共享方式。arg 为获取锁的次数,尝试获取资源。负数表示失败;0 表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。protected boolean tryReleaseShared(int arg) 共享方式。arg 为释放锁的次数,尝试释放资源,如果释放后允许唤醒后续等待结点返回True ,否则返回False 。
一般来说,自定义同步器要么是独占方式,要么是共享方式,它们也只需实现

加锁:
- 通过
ReentrantLock 的加锁方法Lock 进行加锁操作。 - 会调用到内部类
Sync 的Lock 方法,由于Sync#lock 是抽象方法,根据ReentrantLock 初始化选择的公平锁和非公平锁,执行相关内部类的Lock 方法,本质上都会执行AQS 的Acquire 方法。 AQS 的Acquire 方法会执行tryAcquire 方法,但是由于tryAcquire 需要自定义同步器实现,因此执行了ReentrantLock 中的tryAcquire 方法,由于ReentrantLock 是通过公平锁和非公平锁内部类实现的tryAcquire 方法,因此会根据锁类型不同,执行不同的tryAcquire 。tryAcquire 是获取锁逻辑,获取失败后,会执行框架AQS 的后续逻辑,跟ReentrantLock 自定义同步器无关。
解锁:
- 通过
ReentrantLock 的解锁方法Unlock 进行解锁。 Unlock 会调用内部类Sync 的Release 方法,该方法继承于AQS 。Release 中会调用tryRelease 方法,tryRelease 需要自定义同步器实现,tryRelease 只在ReentrantLock 中的Sync 实现,因此可以看出,释放锁的过程,并不区分是否为公平锁。- 释放成功后,所有处理由
AQS 框架完成,与自定义同步器无关。
通过上面的描述,大概可以总结出

// java.util.concurrent.locks.ReentrantLock
static final class NonfairSync extends Sync {
...
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
...
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
具体获取锁的实现方法是由各自的公平锁和非公平锁单独实现的(以
AQS 应用
ReentrantLock 的可重入应用
// java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire
if (c == 0) {
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire
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;
}
从上面这两段都可以看到,有一个同步状态
// java.util.concurrent.locks.AbstractQueuedSynchronizer
private volatile int state;
State 初始化的时候为0 ,表示没有任何线程持有锁。- 当有线程持有该锁时,值就会在原来的基础上
+1 ,同一个线程多次获得锁是,就会多次+1 ,这里就是可重入的概念。 - 解锁也是对这个字段
-1 ,一直到0 ,此线程对锁释放。
J.U.C 中的应用场景
除了上边
同步工具 | 同步工具与 |
---|---|
ReentrantLock | 使用 |
Semaphore | 使用 |
CountDownLatch | 使用 |
ReentrantReadWriteLock | 使用 |
ThreadPoolExecutor |
自定义同步工具
public class LeeLock {
private static class Sync extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire (int arg) {
return compareAndSetState(0, 1);
}
@Override
protected boolean tryRelease (int arg) {
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively () {
return getState() == 1;
}
}
private Sync sync = new Sync();
public void lock () {
sync.acquire(1);
}
public void unlock () {
sync.release(1);
}
}
通过我们自己定义的
public class LeeMain {
static int count = 0;
static LeeLock leeLock = new LeeLock();
public static void main (String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run () {
try {
leeLock.lock();
for (int i = 0; i < 10000; i++) {
count++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
leeLock.unlock();
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
Links
2021- 源码级深挖AQS 队列同步器: 通过理解队列同步器的工作原理,对我们了解和使用这些工具类会有很大的帮助。