AQS是JDK并发包下的一个基础类,或者模板类,JUC下的很多工具类都是基于它实现的。其内部:
- 依靠内部维护一个FIFO的等待队列
- 对于只依赖一个原子值来表示状态的同步机制来说很有用
- 子类继承AQS来修改原子状态,从而实现相关同步操作。
- getState()
- setState()
- compareAndSetState()
AQS支持排它模式和共享模式,等待在不同线程的共享同一个FIFO队列,目前大部分都会只实现一种机制,排它或者共享,JDK中有一个类同时实现了两种机制:ReadWriteLock
想要使用当前的类,重定义其几个方法:
- tryAcquire 尝试获取独占锁,
- tryRelease 尝试释放排它锁
- tryAcquireShared 尝试获取共享锁,返回负数代表失败,返回0代表当前的锁获取成功,但是后续无法获取,返回正数,代表后续的节点仍然可以继续获取
- tryReleaseShared 尝试释放共享锁
- isHeldExclusively 是否排它状态
获取和释放操作本质即变更state。
再真正调用的时候则使用,AQS内部的方法,其会调用我们定义的几个方法,使用时:
- acquire\acquireInterruptibly\tryAcquireNanos 获取排它锁
- acquireShared\acquireSharedInterruptibly\tryAcquireSharedNanos 获取共享锁
- release\releaseShared 释放锁
例如排它锁的实现形式:
Acquire:
while (!tryAcquire(arg)) {
// enqueue thread if it is not already queued;
如果还没有加入队列,那么将当前线程加入队列
// possibly block current thread;
可能block当前的线程
}
Release:
if (tryRelease(arg))
unblock the first queued thread;
// 解锁第一个入队列的线程
JUC的CountdownLatch和ReentrantLock给了我们一个很经典的实现方式,后面我们再分析其具体实现。当前看下CountdownLatch代码:
public class CountDownLatch {
// 实现同步机制
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() {
sync.releaseShared(1);
}
public long getCount() {
return sync.getCount();
}
}
下次再分析下AQS的具体方法含义。