AbstractQueueSynchronizer 是基于 FIFO线程等待队列 的一个同步器开发框架。
这篇文章首先介绍同步器概念,然后介绍AQS的结构原理
并发环境下,Synchronizer用于实现线程之间的协同。具体而言,就是哪个线程应该阻塞,哪个线程应该被唤醒。
常见的同步器实现有:CountdownLatch、CycleBarrier、ReentrantLock等…
使用CountdownLatch进行协同的一个例子:
这里的一个例子是服务初始化,n个initializer并发执行,init方法内调用latch.await()等待所有initializer执行完成。
package org.otaku.example;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
public class ServiceInit {
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(0);
private final CountDownLatch latch;
private final int count;
public ServiceInit(int count) {
latch = new CountDownLatch(count);
this.count = count;
}
public void init() throws InterruptedException {
for (int i = 0; i < count; i++) {
new Initializer().start();
}
latch.await();
System.out.println("all initializers finished!");
}
class Initializer extends Thread {
private final int id = ID_GENERATOR.incrementAndGet();
public void run() {
try {
Thread.sleep(ThreadLocalRandom.current().nextLong(1000, 3000));
} catch (InterruptedException ignored) {
}
System.out.println("initializer-" + id + " finished!");
latch.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
ServiceInit serviceInit = new ServiceInit(5);
serviceInit.init();
}
}
AQS包含以下元素:
acquire方法用于申请互斥资源。
AbstractQueueSynchronizer的acquire方法调用子类实现的tryAquire方法:
//申请互斥资源
public final void acquire(int arg) {
//调用tryAquire,如果返回true,则线程通过
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //如果tryAquire返回false,则线程入队阻塞
selfInterrupt();
}
tryAquire留给子类实现:
//返回true,线程通过;返回false,线程入队阻塞
//调用acquire,tryAquire至少被调用一次,若返回false则入队阻塞,后续被唤醒后
//将继续尝试调用tryAquire,直到成功为止
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
release方法用于释放互斥资源
AbstractQueueSynchronizer的release方法调用子类实现的tryRelease方法:
//释放互斥资源
public final boolean release(int arg) {
//调用tryRelease,返回true,唤醒队头线程;返回false则方法执行结束
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease留给子类实现:
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
Doug Lea在JDK文档中给出了使用AQS的一个例子:简单的不支持重入的互斥锁:
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
//CAS获取锁,从0到1则获取成功
if (compareAndSetState(0, 1)) {
//记录获取锁的线程
setExclusiveOwnerThread(Thread.currentThread());
//返回true,线程通过
return true;
}
//获取锁失败,返回false,线程入队阻塞
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
//将状态设置为0
setState(0);
//返回true,则唤醒队头阻塞线程,重新尝试tryAcquire
return true;
}
// Reports whether in locked state
public boolean isLocked() {
return getState() != 0;
}
public boolean isHeldExclusively() {
// a data race, but safe due to out-of-thin-air guarantees
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Provides a Condition
public Condition newCondition() {
return new ConditionObject();
}
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isLocked(); }
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}
acquireShared方法用于申请共享资源
public final void acquireShared(int arg) {
//1.调用tryAcquireShared,>= 0通过,< 0则进入线程等待队列
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
tryAcquireShared
和tryAcquire不同,这里返回一个int,代表申请到的资源个数。返回<0代表资源申请失败;返回0代表申请资源成功,且后续申请都将失败;返回>0代表后续申请可能成功。
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
releaseShared方法用于释放互斥资源
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
//唤醒阻塞线程
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
使用CountdownLatch,多个线程在latch上等待,当latch被打开,多个线程都被放行,因此在latch上等待即为申请共享资源,而调用countdown方法则是尝试释放资源许可。
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) {
//一旦latch被打开,线程将被放行,否则阻塞
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
//门已被打开,返回false,因为没有线程需要被唤醒
if (c == 0)
return false;
int nextc = c - 1;
//CAS将状态-1
if (compareAndSetState(c, nextc))
//只有状态减到0,才能释放等待线程,否则release都返回false
return nextc == 0;
}
}
}