CountDownLatch是什么?

CountDownLatch如何工作?

在实时系统中的应用场景

应用范例

常见的面试题

CountDownLatch是什么

CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

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

file

以同步方式发消息为例子,同步发送完短信以及推送公众号之后再执行主线程 代码如下:

package org.choviwu.movie.test.countdownlatch;
import java.util.concurrent.CountDownLatch;

/**
 * 发送消息基类
 * @author ChoviWu
 */
public abstract class AbstractMessage {

    /**
     * 设置该变量 并在构造器中初始化
     */
    protected  CountDownLatch countDownLatch ;

    public AbstractMessage(CountDownLatch countDownLatch){
        this.countDownLatch = countDownLatch;
    }

    /**
     * 编写一个发送消息的方法
     * @param user
     */
    public abstract void sendMessage(String user);
}

package org.choviwu.movie.test.countdownlatch;

import java.util.concurrent.CountDownLatch;

/**
 * @author ChoviWu
 * 发送短信
 */
public  class SmsMessage extends AbstractMessage{


    public SmsMessage(CountDownLatch countDownLatch) {
        super(countDownLatch);
    }

    @Override
    public   void sendMessage(String user){
        try {
            //这里是模拟一下线程执行的时间
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("短信已经成功发送给:"+ user);
        //发送成功通知主线程 -1
        this.countDownLatch.countDown();
    }
}

package org.choviwu.movie.test.countdownlatch;
import java.util.concurrent.CountDownLatch;

/**
 * @author ChoviWu
 */
public  class WechatMessage extends AbstractMessage{


    public WechatMessage(CountDownLatch countDownLatch) {
        super(countDownLatch);
    }

    @Override
    public   void sendMessage(String user ){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("微信服务号已经成功发送给:"+ user);
        //发送成功通知主线程 -1
        this.countDownLatch.countDown();
    }
}

写一个测试类测试一下:

package org.choviwu.movie.test;

import com.google.common.collect.Lists;
import org.choviwu.movie.test.countdownlatch.AbstractMessage;
import org.choviwu.movie.test.countdownlatch.SmsMessage;
import org.choviwu.movie.test.countdownlatch.WechatMessage;

import java.util.List;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {


    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(2);

        List<AbstractMessage> list = Lists.newArrayList();
        list.add(new SmsMessage(countDownLatch));
        list.add(new WechatMessage(countDownLatch));
        long startTime = System.currentTimeMillis();
            //开启两个线程分别执行发送短信和推送服务号
            list.forEach(message ->{
                new Thread(()-> {
                message.sendMessage("奕仁");
            }).start();
        });
        try {
            //主线程在等待
            System.out.println("主线程预备阶段");
            countDownLatch.await();
            System.out.println("时间差:"+(System.currentTimeMillis()-startTime)/1000 + "秒");
            System.out.println("子线程执行完通知主线程完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

file

以上就是CountDownLatch的

框架中用到CountDownLatch

基于Zookeeper的分布式锁(zk的watcher机制)