java 并发工具包 -倒计数CountDownLatch

简介

CountDownLatch 是一个同步器,翻译过来就是倒计数,意思就是用倒数来计数,当为0的时候结束。

源码分析

public class CountDownLatch {
    /**
     * 同步器,继承于aqs用来计数
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        //初始化设置状态,即设置初始化计数器
        Sync(int count) {

            setState(count);
        }
        //获取state 即获取当前的计数器
        int getCount() {
            return getState();
        }
//重写父类方法,尝试判断当前值是否为0  
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
    //重写父类方 尝试判断是否-1是否为0
        protected boolean tryReleaseShared(int releases) {

            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                //cas 替换state值,如果当前不匹配则循环直至state为0或者匹配成功
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

   //初始化  其实就是去初始化sync
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }


    public void await() throws InterruptedException {
    //如果计数器还大于0则阻塞当前线程  直到计数器=0为止
        sync.acquireSharedInterruptibly(1);
    }

    //要么一直阻塞到时间过期,要么计数器=0
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

      //计数器-1  如果-1后=0 则释放线程
    public void countDown() {
        sync.releaseShared(1);
    }

        //获取当前计数器
    public long getCount() {
        return sync.getCount();
    }


    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }
}

CountDownLatch源码之所以简单得易于AbstractQueuedSynchronizer 同步器,基本上所有的操作都是由AbstractQueuedSynchronizer 处理

简单例子

public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    countDownLatch.await();
                    System.out.println("释放线程1");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    countDownLatch.await();
                    System.out.println("释放线程2");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("计数器-1");
                countDownLatch.countDown();

            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("计数器-1");
                countDownLatch.countDown();

            }
        }).start();
    }

}

总结:

我们前面讲到CyclicBarrier同步器,两者功能类似,都是倒计数,当为0时,释放阻塞线程,但是CyclicBarrier针对的是主线程或者说一个线程,CountDownLatch针对的一组线程(上面例子中有两个线程);
CyclicBarrier可以接收Runnable参数,CountDownLatch不能;
CyclicBarrier通过执行await-1并且一直阻塞直到0大家一起接着执行,CountDownLatch通过countDown,不会阻塞;
这么说吧
CyclicBarrier :主线程和子线程最后会同时执行(如果await后面没有业务处理,和 CountDownLatch效果也类似)
CountDownLatch:一般子线程不管主线程,自己先执行掉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值