Java并发编程之AQS

29 阅读2分钟

前言

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state.

这段话是AbstractQueuedSynchronizer源码注释中的一段,意思是AbstractQueuedSynchronizerAQS抽象队列同步器)提供了一个基于FIFO等待队列来实现阻塞锁和相关同步器的框架,而且这个类对于很多种依赖于单个原子int值表示状态的同步器是一个很有用的基础。

简言之,AQS提供了一个框架来实现锁,通过一个原子int值表示加锁状态,阻塞的线程进入FIFO队列进行等待。

主要方法

private volatile int state;
// 获取state
protected final int getState() {
    return state;
}
// 修改state
protected final void setState(int newState) {
    state = newState;
}
// 通过CAS修改state
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

上面是state属性和相关方法,state表示同步器状态,也就是是否加锁或加锁次数。

protected boolean isHeldExclusively()

AQS对于资源的共享有两个种方式,分别是独占方式和共享方式。独占表示只有一个线程可以执行,其他线程只能等待;共享方式下多个线程都可以执行。isHeldExclusively表示是否在独占模式下被占用。

protected boolean tryAcquire(int arg)

尝试在独占模式下进行加锁。

protected int tryAcquireShared(int arg)

尝试在共享模式下进行加锁

protected boolean tryRelease(int arg)

尝试在独占模式下进行解锁

protected boolean tryReleaseShared(int arg)

尝试在共享模式下进行解锁

使用AQS的思路就是继承AbstractQueuedSynchronizer类并实现以上操作锁(state)的方法就可以了。

应用举例

Java中很多同步器类都是通过AQS来实现的,比如ReentrantLockCountDownLatch

ReentrantLock实现原理是state初始值为0表示没有加锁,线程调用tryAcquire方法尝试获取锁,获取成功就把state修改为1,并把独占拥有者线程exclusiveOwnerThread属性值标记为当前线程,在持有锁期间还可以重复获取锁,每获取一次就把state加1,每释放一次锁就把state1,这就是ReentrantLock类是可重入锁的原因,直到state0时其他线程才能获取锁成功。锁释放前其他锁尝试获取锁失败,就会进入阻塞队列进行等待。

CountDownLatch的基本原理是初始化时把state设为n,每调用一次countDown方法就把state1,所以当countDown次数和n相等时,state的值就是0了,就会唤醒主线程继续向下执行。