CountDownLatch的原理

    今天在学习ZooKeeper的实例的时候,发现了CountDownLatch这个类,那么这个类又是如何使用的呢?以及这个类的原理是什么?我们首先看一下简单的demo:


public class CountDownLatchTest {

    static class Student implements Runnable {

        CountDownLatch  countDownLatch  = null;

        /**
         * 
         */
        public Student(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            try {
                Thread.sleep( 1000 );
                System.out.println( "交卷了!" );
                countDownLatch.countDown();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

    static class Teacher implements Runnable {
        CountDownLatch  countDownLatch  = null;

        /**
         * 
         */
        public Teacher(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run() {
            try {
                countDownLatch.await();
                System.out.println( "完成考试了" );
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

    public static void main(String args[]) {
        CountDownLatch countDownLatch = new CountDownLatch( 4 );
        Executor executor = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() + 1 );
        executor.execute( new Student( countDownLatch ) );
        executor.execute( new Student( countDownLatch ) );
        executor.execute( new Student( countDownLatch ) );
        executor.execute( new Student( countDownLatch ) );
        executor.execute( new Teacher( countDownLatch ) );

    }
}

    如上面所示,我们首先定义了定义了一个Student的线程,然后在休眠一段时间,执行CountDownLatch.countDown(),然后定义了Teacher的线程,直接等待。CountDownLatch的值降低到0自动会唤醒。
    其实CountDownLatch类似于一个计数器,只不过这个计数器同时只有一个线程去操作。
    这个类适用于当某个线程等待其他n个线程完成任务的时候再执行相应的任务。
    那么CountDownLatch的实现原理是什么呢?我们来看一下源码,当我们初始化CountDownLatch的时候会发生什么事情:


  public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count <0");
        this.sync = new Sync(count);
    }

    CountDownLatch在初始化的时候,将内部变量sync进行赋值,sync的变量类型是Sync,那么我们看看Sync的实现


 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) {
            return (getState() == 0) ? 1 : -1;
        }

        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;
            }
        }
    }

    我们可以看到Sync也是基于AQS实现的共享锁。那么当调用CountDownLatch.countDown()会发生什么?


  public void countDown() {
        sync.releaseShared(1);
    }

    可以看出来,CountDownLatch.countDown()就是调用AQS的releaseShared(int arg),然后releaseShared(int arg)可以保证将数量原子地减一。
    那么CountDownLatch.await()又是如何实现的呢?


   public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    await()调用的是sync的acquireSharedInterruptibly(int arg)


    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

    在Sync重写了tryAcquireShard(arg),当计数器数字不为0的时候返回-1,因此调用doAcquireShardInterruptibly(arg),而doAcquireShardInterruptibly则会将本线程加载到执行链条的末尾,当别的线程执行完后才会执行,关于AQS的源码解析我们下个文章再看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值