首页 > 技术文章 > Java并发编程-JUC-CountDownLatch 倒计数门闩器-等待多线程完成再放行 -一次性使用

zhazhaacmer 2019-08-16 18:52 原文

如题 (总结要点 ,看不懂下面有更多解释, 参考书籍《Java并发编程实战》)

  • CountDownLatch 倒计数门闩器
  • 让1-n-1个线程等待主线程完成工作。(Excel的多个Sheet的解析,最终等待解析完毕后;要实现主线程等待所有线程完成sheet解析操作,最简单的就是join )
    常用API
  • CountDownLatch latch = new CountDownLatch(2); // 新建一个倒计数门闩器 ,常用于迫使主线程进入等待 ;设置N个结点 ,n个线程或者步骤
  • latch.countDown(); // 计数器-1
  • latch.await(1000, TimeUnit.MILLISECONDS); //阻塞当前线程(常为主线程),直到计数器变为0
    区分
    • CyclicBarrier循环栅栏,维持最低的并发,让多个线程同时并发执行。每调用一次await()方法都将使阻塞的线程数+1,只有阻塞的线程数达到设定值时屏障才会打开,允许阻塞的所有线程继续执行。

适用场景总结

例子一

  • 比如导出一份Excel, 共有10万行, 拆分出10K行 * 10个线程来解析(导入/导出)处理; 主线程来创建(或提交)任务并分配10个新线程来处理;
  • 由于主线程分配完任务后就继续往下执行了, 其他的那10个新的线程还需要等待一段时间; 那这段时间差怎么处理??
  • Excel的多个Sheet的解析,最终等待解析完毕后再进行汇总处理, 主线程需要进行汇总处理, 那么就使用CountDownLatch 倒计数门闩器,来处理就很合理了.

例子二

  • 需要分别统计 sort_id 为1-1万的某个表的字段数量, 使用多线程处理,调用10个线程并发统计,每个统计%K的范围; 倒计数门闩就很合适, 最后处理完了,主线程再进行处理/封装再返回.
  • 依次类推

常用api

//构造器, 参数count为计数值
public CountDownLatch(int count) {  };  

//调用await()方法的线程会被挂起(一般是主线程),它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };   

//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  

//将count值减1
public void countDown() { };  

1.测试1 简单测试


public class Test03_countdownlatch {
    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                 // 睡眠可以开启, Thread.sleep(1000L);
                System.out.println("hello ");
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        System.out.println("all thread finish");
    }
}

2. 结果1 : 线程还没有来得及执行完毕,主线程就结束了(JVM关闭了),所以先打印的finish ; 如果子线程数量更多的话, 子线程就不一定能打印完.自己试试! 或者

all thread finish
hello 
hello 

3.测试2 迫使主线程通过子线程的join方法等待当前的子线程执行完毕

 public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello ");
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);

        thread1.start();
        thread2.start();

        try {
            // 迫使主线程通过join方法等待当前的子线程执行完毕
            thread1.join();
            // 主线程第二次等待
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("all thread finish");
    }

测试结果2

hello 
hello 
all thread finish

测试3 使用倒计数门闩器

public static void main(String[] args) {

        Runnable runnable = () -> System.out.println("hello ");
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);

        // 使用倒计数门闩器 ,迫使主线程进入等待 ;设置N个结点 ,n个线程或者步骤都可以
        CountDownLatch latch = new CountDownLatch(2);
        thread1.start();
        latch.countDown();
        thread2.start();
        latch.countDown();

        try {
            // 阻塞当前线程,直到计数器变为0; await(long time);也可以带时间!
            latch.await(1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("all thread finish");


    }

测试结果3

hello 
hello 
all thread finish

推荐阅读