读前必看AQS原理——http://blog.csdn.net/qq_31957747/article/details/74910939
一、倒计时器CountDownLatch
这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束再开始执行。CountDownLatch是共享模式的。
构造方法:
CountDownLatch(int count):count就是计数的次数
主要方法:
void await():让当前线程等待,直到倒计时结束
long getCount():获取当前剩余的计数的次数
void countDown():计数减一
下面看一个例子:
构造方法:
CountDownLatch(int count):count就是计数的次数
主要方法:
void await():让当前线程等待,直到倒计时结束
long getCount():获取当前剩余的计数的次数
void countDown():计数减一
下面看一个例子:
public class CountDownLatchDemo implements Runnable {
private static CountDownLatch cdt = new CountDownLatch(10);
@Override
public void run() {
try{
Thread.sleep(1000);
System.out.println("完成一次计数");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
cdt.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatchDemo demo = new CountDownLatchDemo();
ExecutorService exec = Executors.newFixedThreadPool(10);
for(int i = 0;i<10;i++){
exec.submit(demo);
}
cdt.await();
System.out.println("计数完毕");
exec.shutdown();
}
}
运行结果:
二、CountDownLatch源码分析
2.1 构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}
可以看到计数的次数count直接被赋值给了state。
2.2 await()
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
可以看到是AQS共享模式获取资源的方法,只不过是可以被中断的。再看这个方法:
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
接下来看CountDownLatch中对tryAcquireShared方法的重写。
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; //倒计时结束了就返回1,否则返回-1
}
doAcquireSharedInterruptibly方法就不再重复了,AQS那篇文章有介绍。
总结一下await():
调用await的线程加入到CountDownLatch的资源获取,不过CountDownLatch对尝试获取资源的方法进行了重写,只有当倒计时结束后才能获取资源,否则在等待队列中等着。因此上面那个例子的主线程就会等待倒计时结束,才继续往下运行。
2.3 countDown()
public void countDown() {
sync.releaseShared(1);
}
再看releaseShared方法。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared(); //倒计时结束后,唤醒后继排队线程,也就是调用await的那个线程
return true;
}
return false;
}
看下CountDownLatch对tryReleaseShare方法的重写。
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) { //自旋
int c = getState();
if (c == 0) //已经为0了不能再减数了
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc)) //这个自旋周期内别的线程没有contDown
return nextc == 0; //倒计时结束返回true,否则返回false
}
}
doReleaseShared()方法就不贴了,AQS那篇也讲过,作用也就跟上面注释的那样,唤醒后继排队线程,也就是调用await的那个线程。