前面一篇文章Semaphore讲了基于AQS共享锁实现的信号量工具,今天再讲另一个同样基于AQS共享锁实现的计数器工具——CountDownLatch:
/**
* CountDownLatch基于CAS中的共享锁,常用有如下几个方法:
* 1. CountDownLatch(3): 设置共享锁数量
* 2. await(): 检查当前共享锁数量,如果锁数量等于0,就继续执行,反之如果锁数量不为0,就放入同步队列中等待,线程挂起
* 3. countDown(): 释放共享锁,如果锁全部释放,就唤醒下一个节点线程(注意共享锁在在唤醒后继续执行时,会再次唤醒下一个共享线程,这样就实现了依次唤醒所有等待的线程)
*/
public class CountDownTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
service.execute(() -> {
try {
System.out.println("thread: " + Thread.currentThread().getName() + " 等待命令");
// 内部使用的是共享锁,多个线程可以同时调用
// 如果锁数量不为0,就放到队列中等待
cdOrder.await();
System.out.println("thread: " + Thread.currentThread().getName() + " 接收到命令,正在比赛");
Thread.sleep((long) (Math.random() * 10000));
cdAnswer.countDown();
System.out.println("thread: " + Thread.currentThread().getName() + " 比赛结束");
} catch (Exception e) {
e.printStackTrace();
}
});
}
try {
Thread.sleep((long) (Math.random() * 10000));
System.out.println("thread: " + Thread.currentThread().getName() + " 准备发送命令");
// 释放锁,如果锁都释放了,就唤醒下一个节点
cdOrder.countDown();
System.out.println("thread: " + Thread.currentThread().getName() + " 已发送命令");
cdAnswer.await();
System.out.println("thread: " + Thread.currentThread().getName() + " 全部比赛结束");
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
await等待
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
/**
* 这里只是判断了锁数量是否为0
* 如果锁数量为0,就继续往下走
* 反之,就放到同步队列中等待
*/
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
countDown计数减一
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
/**
* 释放锁,锁数量减一
*/
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;
}
}