首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >并发是个什么鬼之同步工具类CountDownLatch

并发是个什么鬼之同步工具类CountDownLatch

作者头像
小柒2012
发布2019-12-05 18:58:57
3090
发布2019-12-05 18:58:57
举报
文章被收录于专栏:IT笔记IT笔记

CountDownLatch 又是大神 Doug Lea的又一神作,正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

f65cc83b7b4664916fad5d1398a36005.png
f65cc83b7b4664916fad5d1398a36005.png

源码分析

源码位于rt.java中的java.util.concurrent包中。

1、CountDownLatch:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

中文解释:也就是说主线程在等待所有其它的子线程完成后再往下执行

2、构造函数:CountDownLatch(int count)//初始化count数目的同步计数器,只有当同步计数器为0,主线程才会向下执行

主要方法:void await()//当前线程等待计数器为0 boolean await(long timeout, TimeUnit unit)//与上面的方法不同,它加了一个时间限制。 void countDown()//计数器减1 long getCount()//获取计数器的值

3.它的内部有一个辅助的内部类:sync. 它的实现如下:

/**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    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;
            }
        }
    }

4.await()方法的实现

public void await() throws InterruptedException {
   sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        //调用3中的tryAcquireShared()方法
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);//加入到等待队列中
    }

5.countDown()方法的实现

public void countDown() {
        sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
//调用3中的tryReleaseShared()方法
        if (tryReleaseShared(arg)) {
        //解锁
            doReleaseShared();
            return true;
        }
        return false;
}

应用场景

比如主任务是一个比较复杂的运算,为了节约时间,我们可以拆分成多个子任务,多线程同时执行,最终统一汇总任务。

其实生活也有类似的场景,比如马拉松赛跑,我们不可能按顺序依次跑步,这样得跑到猴年马月。一般来说都是大家听到发号命令一起跑,最终比赛结束,统一汇总成绩。

代码案例

下面看一个例子大家就清楚CountDownLatch的用法了:

/**
 * CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
 * 构造方法参数指定了计数的次数
 * countDown方法,当前线程结束执行后调用,计数减一 
 * awaint方法,调用此方法会一直阻塞当前线程,直到计时器的值为0
 * 创建者 科帮网
 * 创建时间    2017年8月15日
 *
 */
public class CountDownLatchDemo {
    final static SimpleDateFormat sdf = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
    
    final static String startTime = sdf.format(new Date());

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(2);// 两个赛跑者
        Runer runer1 = new Runer("刘翔", 5000, latch);
        Runer runer2 = new Runer("罗伯斯", 8000, latch);
        runer1.start();//刘翔   开始跑步
        runer2.start();//罗伯斯 开始跑步
        latch.await();// 等待所有人赛跑结束
        System.out.println("all runer done at " + sdf.format(new Date()));
    }

    static class Runer extends Thread {
        String runerName;
        int runTime;
        CountDownLatch latch;

        public Runer(String runerName, int runTime, CountDownLatch latch) {
            this.runerName = runerName;
            this.runTime = runTime;
            this.latch = latch;
        }

        public void run() {
            System.out.println("Runer " + runerName + " do run begin at "
                    + startTime);
            doRun();//跑步
            System.out.println("Runer " + runerName + " do run complete at "
                    + sdf.format(new Date()));
            latch.countDown();// 终点结束,计数器减一

        }

        private void doRun() {
            try {
                Thread.sleep(runTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码分析
  • 应用场景
  • 代码案例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档