java多线程中CountDownLatch的介绍

今天在看使用zookeeper实现简单分布式锁的文章中看到了CountDownLatch这个类,但是以前没有用过就自己学习了下。

CountDownLatch类是一个同步工具类,它允许一个或者多个线程一直等待直到其他线程执行完成之后然后再执行。

其中countDown()方法是当一个被等待的执行线程数执行完成了之后减1,await()是让调用函数被阻塞,直到被等待的线程执行完成countDown()减为0的时候等待的线程才会从阻塞状态变为运行状态。

下面设计一个简单的例子:

  • 1.创建一个抽象的base线程类BaseThread
package com.lijie.thread;

import java.util.concurrent.CountDownLatch;

public abstract class BaseThread implements Runnable{

    protected CountDownLatch cdl;

    protected String serverName;

    protected long time;

    /**
     * 构造函数
     * @param cdl
     * @param serverName
     */
    public BaseThread(CountDownLatch cdl, String serverName,long time) {
        super();
        this.cdl = cdl;
        this.serverName = serverName;
        this.time = time;
    }

    @Override
    public void run() {
        callBack();
    }

    /**
     * 回调函数
     */
    public abstract void callBack();

}
  • 2.创建一个WorkThread继承上面的BaseThread,并且实现callBack()函数

注意:cdl.countDown()方法最好是放在finally块里面,防止有异常程序中断,CountDownLatch的计数一直不为0,导致后面的线程无法执行,或者等待超时。

package com.lijie.thread;

import java.util.concurrent.CountDownLatch;

public class WorkThread extends BaseThread{

    public WorkThread(CountDownLatch cdl, String serverName, long time) {
        super(cdl, serverName, time);
    }

    @Override
    public void callBack() {
        try {
            System.out.println("开始"+serverName);
            Thread.sleep(time);
            System.out.println("完成"+serverName);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            cdl.countDown();
        }
    }

}
  • 3.创建主函数
package com.lijie.thread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainClass {

    private static CountDownLatch cdl;

    public static void main(String[] args) throws InterruptedException {

        cdl = new CountDownLatch(3);

        BaseThread b1 = new WorkThread(cdl,"吃饭",7000);
        BaseThread b2 = new WorkThread(cdl,"睡觉",3000);
        BaseThread b3 = new WorkThread(cdl,"打豆豆",5000);

        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.execute(b1);
        executor.execute(b2);
        executor.execute(b3);

        cdl.await();

        System.out.println("开始主函数!");
        executor.shutdown();

    }
}
  • 4.执行主函数,并查看结果
    这里写图片描述

  • 5.为什么使用抽象类

这里使用抽象类,主要是为了定义一个callBack()的动作规范,多个类去继承base类的时候都需要实现里面的callBack()方法,这样就能规范子类的一些必须定义的行为,而且子类又可以自己定义这些行为,这样设计类的层级结构、扩展性都很好。


版权声明:本文为qq_20641565原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。