Java高并发编程基础三大利器 - CountDownLatch

1. 什么是CountDownLatch

CountDownLatch是一个线程倒计时锁。

CountDownLatch是通过一个计数器来实现的,计数器的初始值是线程的数量。
每当一个线程执行完毕后,计数器的值就减1,
当计数器的值为0时,表示所有线程都执行完毕,
然后在闭锁上(调用await方法的线程)等待的线程就可以恢复工作了。

 

2. 应用场景


把一个大任务拆分N个部分,让多个工作线程(Worker)执行。
每个工作线程(Worker)执行完自己的部分计数器就减1。
当所有子部分都完成后,主线程才继续向下执行。

例子代码:

public class TestCountDownLatch1 {
     public static void main(String[] args) throws InterruptedException {
          int count = 3;
          CountDownLatch countDownLatch = new CountDownLatch(count);
          for (int i = 0; i < count; i++) {
               final int index = i;
               new Thread(() -> {
                    try {
                         Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(1000));
                         System.out.println("finish" + index + Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                         e.printStackTrace();
                    }finally{
                        countDownLatch.countDown();
                    }
               }).start();
          }

         // 主线程在阻塞,当计数器==0,就唤醒主线程往下执行
          countDownLatch.await();
          
          System.out.println("主线程:在所有任务运行完成后,进行结果汇总");
     }
}

 

更实际的例子:

我们打开一个电商的个人中心页面。
在该页面, 我们需要调用:
1. 用户信息接口
2. 用户订单接口
3. 用户会员信息等接口

然后合并后一起给到前端。
假设每个接口最长耗时为1s,如果我们同步调用的话最大耗时时间是3s,
如果我们采用异步调用然后合并结果,所以最大的耗时时间是3s。
每个接口调用返回数据后调用countDown方法,让计数器进行减1,
当把计数器减为0时的这个线程会去唤醒主线程,让它继续往下走。

 

3. CountDownLatch 实现原理

CountDownLatch是通过AQS的state字段来实现的一个计数器。

计数器的初始值(state的值)为new CountDownLatch设置的数量,
每次调用countDown的时候,state的值会进行减1,
最后某个线程将state值减为0时,会把调用了await()进行阻塞等待的线程进行唤醒。
CountDownLatch重写了tryReleaseShared这个方法,
只有当state这个字段被设置为0时,也就是tryReleaseShared返回true的情况就会执行doReleaseShared方法,
把调用了await的线程进行唤醒。


部分源码:
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

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

 



 

 

 

 
posted @ 2021-04-20 22:08  Master HaKu  阅读(226)  评论(0编辑  收藏  举报