AQS是j.u.c中几个并发类的基础,它们都继承了AbstractQueuedSynchronizer类,并且在其中实现了几个接口,然后在并发类中使用AQS的方法就可以达到操作线程阻塞或者唤醒的目的。这篇文章记的就是这些子类实现的接口是如何和AQS搭配起来使用的,从而实现AQS的效果。
首先来看需要自定义同步器自己实现的接口:
独占模式:
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
共享模式:
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
那么子类实现的这些方法和AQS中的又是怎么搭配起来使用从而能让线程阻塞或者是唤醒的呢?
AQS中:
独占模式下:
获取资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
这个是获取资源。简单的来说,就是在子类中实现的tryAcquire()方法返回false(资源获取失败)后,则该线程会进入等待队列中阻塞。
释放资源
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
这个是释放资源。简单的来说,就是在子类中实现的tryRelease()方法在返回true之后,会唤醒后继节点。
共享模式下:
获取资源
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
此方法为共享模式下获取资源,在AQS中定义了,如果资源获取失败,tryAcquireShared()返回<0;如果获取成功但是没有资源了,则返回0;如果成功且有资源,则返回>0;那么我们可以看到,如果tryAcquireShared()<0,就会阻塞当前线程。
释放资源
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
此方法为共享模式下的释放资源,如果子类中实现的tryReleaseShared()方法返回true,则会唤醒后继节点。
总的来说,tryAcquire()/tryAcquireShared()方法返回值false或者是<0,则会挂起当前请求的线程(当然实际上条件还更复杂)。tryRelease()/tryReleaseShared()方法返回true则会唤醒等待队列中的后继节点(实际条件更复杂,可以参考下面的文章)。后面会根据这个大致的结论来一步步分析CountDownLatch,Semaphere,CyclicBarrier
个人觉得,理解这些子类需要实现的方法和AQS之间的关系,对理解J.U.C中的各个类的原理有帮助。但是具体的AQS里面每个方法的原理,之间的协作,可以参考这篇文章:http://www.cnblogs.com/waterystone/p/4920797.html