AQS(队列同步器)是用来构建锁或其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,并通过内置的FIFO 队列来完成资源获取线程的排队工作。
前提
AQS设计基于模板方法模式,即使用者仅需继承同步器并重写指定方法,再调用同步器提供的模板方法(模板方法会调用使用者重写的方法),即可实现自定义同步组件。
重写AQS指定方法,需使用AQS提供的以下3个方法访问或修改同步状态:
- getState():获取当前同步状态;
- setState(int newState):设置当前同步状态;
- compareAndSetState(int expect, int update):使用CAS设置当前状态,保证状态设置的原子性。
AQS可重写的方法:
方法名称 | 描述 |
---|---|
protected boolean tryAcquire(int arg) | 独占式获取同步状态,实现该方法需查询当前同步状态并判断当前同步状态是否符合预期,然后再CAS设置同步状态。 |
protected boolean tryRelease(int arg) | 独占式释放同步状态,等待获取同步状态的线程将有机会获取同步状态。 |
protected int tryAcquireShared(int arg) | 共享式获取同步状态,返回值≥0,表示获取成功,反之失败 |
protected boolean tryReleaseShared(int arg) | 共享式释放同步状态 |
protected boolean isHeldExclusively() | 当前同步器是否在独占模式下被线程占用,一般表示是否正在被当前线程所占用 |
注:上述方法中的参数arg的解释为:
arg the acquire argument. This value is always the one passed to an acquire method, or is the value saved on entry to a condition wait. The value is otherwise uninterpreted and can represent anything you like.
个人理解:可以设置为任意值,用以表示同步状态,例如表示同一线程进入同一个锁arg次。
AQS提供的模板方法
方法名称 | 描述 |
---|---|
public final void acquire(int arg) | 独占式获取同步状态,获取成功则返回,否则进入同步队列等待,该方法会调用重写的tryAcquire方法 |
public final void acquireInterruptibly(int arg) | 同上,但响应中断。当前线程未获取到同步状态而进入同步队列,若当前线程被中断,则该方法会抛出InterruptedException并返回 |
public final boolean tryAcquireNanos(int arg, long nanosTimeout) | 在上面的方法上增加了超时限制 |
public final void acquireShared(int arg) | 共享式获取同步状态,与独占式的主要区别为,同一时刻可以有多个线程获取到同步状态 |
public final void acquireSharedInterruptibly(int arg) | 同上,但响应中断 |
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) | 在上面方法的基础上加了超时限制 |
public final boolean release(int arg) | 独占式释放同步状态,该方法在释放同步状态后,将同步队列中的第一个节点所包含的线程唤醒 |
public final boolean releaseShared(int arg) | 共享式释放同步状态 |
public final Collection<Thread> getQueuedThreads() | 获取等待在同步队列上的线程集合 |
AQS中节点的等待状态(waitStatus)
waitStatus | value | 描述 |
---|---|---|
CANCELLED | 1 | 在同步队列中等待的线程等待超时或者被中断,需要从同步队列中取消等待,节点进入该状态后就不会变化。 |
SIGNAL | -1 | 后继节点处于等待状态(被挂起),而当前节点的线程如果释放了同步状态或被取消,将会通知后继节点,使后继节点得以运行。 |
CONDITION | -2 | 节点处于等待队列中,节点线程等待在Condition上,当其他线程对Condition调用了signal方法后,该节点将会从等待队列转移到同步队列中,加入到对同步状态的获取中 |
PROPAGATE | -3 | 表示下一次共享式同步状态获取将会无条件传播下去 |
INITIAL | 0 | 初始状态 |