多线程之倒计时器CountDownLatch及原理

读前必看AQS原理——http://blog.csdn.net/qq_31957747/article/details/74910939


一、倒计时器CountDownLatch

这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束再开始执行。CountDownLatch是共享模式的。


构造方法:
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及原理_第1张图片


二、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的那个线程。













你可能感兴趣的:(并发)