原文出处:http://blog.chenlb.com/2008/11/join-or-countdownlatch-make-main-thread-wait-all-sub-thread.html
在编写多线程的工作中,有个常见的问题:主线程(main) 启动好几个子线程(task)来完成并发任务,主线程要等待所有的子线程完成之后才继续执行main的其它任务。
默认主线程退出时其它子线程不会停,如果想让main退出时其它子线程终止,可以用subThread.setDaemon(true) 设置子线程为“守护线程”。但现在要的是主线程等待所有子线程完成后,还要执行其它操作(比如:结果合并)。记得可以用join()方法来等待所有子线程 完成后,才继续执行。如果不用join(),main线程与子线程是并发的,要稍加处理使main线程暂停。简单点用Thread.sleep(long millis) 了,当然用“等待-通知”机制也可以。
下面是用join的实现main等待所有子线程完成了,示例代码:WaitAllSubThread.java。
- package com.chenlb;
- import java.util.Random;
- /**
- * @author chenlb 2008-11-1 下午11:32:43
- */
- public class WaitAllSubThread {
- /*int liveThreadNum;//记录运行的子线程数
- */
- int n; //工作线程数
- public WaitAllSubThread(int n) {
- this.n = n;
- }
- class Worker implements Runnable {
- String name;
- int sleep;
- public Worker(String name, int sleep) {
- this.name = name;
- this.sleep = sleep;
- }
- public void run() {
- /*upLive(); //计算此线程已经工作.
- */
- System.out.println(name+", start to work.");
- try {
- Thread.sleep(sleep); //虚拟工作. 10s 随机时间
- } catch (InterruptedException e) {
- System.out.println(name+" interrupted.");
- }
- System.out.println(name+", end to work ["+sleep+"] sleep.");
- /*downLive(); //此线程工作完成
- */
- }
- }
- /* //记录线程数的同步方法.
- private synchronized void downLive() {
- liveThreadNum--;
- }
- private synchronized void upLive() {
- liveThreadNum++;
- }
- private synchronized boolean isLive() {
- return liveThreadNum > 0;
- }*/
- public void run() {
- System.out.println("-------------main run start-------------");
- int sleepSaid = 10 * 1000; //每个工作线程虚拟工作最大时间
- Random rm = new Random();
- for(int i=0; i<ths.length; i++) {
- ths[i] = new Thread(new MyTask(rm.nextInt(sleep)+1));
- ths[i].start();
- }
- for(Thread th : ths) {
- try {
- th.join();//join方式
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- /*//等待所有工作线程完成.
- while(isLive()) {
- try {
- Thread.sleep(1000); //每隔1s查看下是否所有线程完成.
- } catch (InterruptedException e) {
- System.out.println("main thread sleep interrupted.");
- }
- }*/
- System.out.println("---------------main run end--------------");
- }
- public static void main(String[] args) {
- WaitAllSubThread wast = new WaitAllSubThread(10);
- wast.run();
- }
- }
如果不用join,上面的代码会使先输出“main run end”,原因是:main 与 所有sub thread并发工作,不等待所有子线程继续工作。而所有子线程完成了,main线程才会退出。
用比较笨的方式:把上面/* */的注释去掉,把 th.join();块注释掉。这样可以使等待所有子线程完成了才去执行其它后续的(比如:这里是输出“main run end”)。分析:程序中加工作的子线程的计数(liveThreadNum)。main不断轮询是否所有子线程完成,所有完成就执行剩下的。
上面的是昨天写的,今天发现一个更加简洁的方式去处理main线程阻塞(等待所有子线程),那就是java.util.concurrent.CountDownLatch类。现在重新实现上面的功能,CountDownLatchUse.java。
- package com.chenlb;
- import java.util.Random;
- import java.util.concurrent.CountDownLatch;
- /**
- * @author chenlb 2008-11-1 下午11:43:31
- */
- public class CountDownLatchUse {
- final CountDownLatch downLatch;
- int n; //工作线程数
- public CountDownLatchUse(int n) {
- this.downLatch = new CountDownLatch(n);
- this.n = n;
- }
- class Worker implements Runnable {
- String name;
- int sleep;
- public Worker(String name, int sleep) {
- this.name = name;
- this.sleep = sleep;
- }
- public void run() {
- System.out.println(name+", start to work.");
- try {
- Thread.sleep(sleep); //虚拟工作. 10s 随机时间
- } catch (InterruptedException e) {
- System.out.println(name+" interrupted.");
- }
- System.out.println(name+", end to work ["+sleep+"] sleep.");
- meDone(); //某个工作线程完成
- }
- }
- private void meDone() {
- downLatch.countDown();
- }
- public void run() {
- System.out.println("-------------main run start-------------");
- int sleepSaid = 10 * 1000; //每个工作线程虚拟工作最大时间
- Random rm = new Random();
- for(int i=0; i<n; i++) {
- new Thread(new Worker("worker-"+i, rm.nextInt(sleepSaid)+1)).start();
- }
- try {
- downLatch.await(); //等待所有工作线程完成.
- } catch (InterruptedException e) {
- System.out.println("main interrupted.");
- }
- System.out.println("---------------main run end--------------");
- }
- public static void main(String[] args) {
- CountDownLatchUse mtu = new CountDownLatchUse(10);
- mtu.run();
- }
- }
CountDownLatch.countDown();完成线程的计数。CountDownLatch.await();完成了主线程阻塞。简洁就是好,以后就这种方式了。
相关推荐
然后,创建一个固定数量的线程池,使用 CountDownLatch 控制主线程等待所有任务完成;最后,循环迭代分片区间,将分片任务提交到线程池中处理。在每个任务中,使用 ReadRowHolder 对象实现分片读取 Excel 数据,并...
mybaits 多线程 实现数据批量插入 (运用CountDownLatch实现闭锁) 1、mybatis批处理 2、数据分批量查询 3、数据分批量插入
利用 CountDownLatch 类实现线程同步,而不用回调机制。详见我的博文 http://blog.csdn.net/kroclin/article/details/37956949
主要为大家详细介绍了使用CountDownLatch等待多线程全部执行完成,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
CountDownLatch与thread.join()的区别
NULL 博文链接:https://cpjsjxy.iteye.com/blog/2272451
主线程等待多个线程完成 4.1 场景介绍 4.2 使用CountDownLatch实现等待 CountDownLatch的其他应用场景 5.1 倒计时计时器 5.2 同时开始任务 5.3 等待多个资源就绪 CountDownLatch与CyclicBarrier的对比 最佳实践与...
- 主线程必须在启动其他线程后立即调用 CountDownLatch.await() 方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务为止。 - 其他 N 个线程必须引用闭锁对象,因为它们如果完成了任务需要...
CountDownLatch可以实现一个线程等待多个线程、多个线程等待一个线程、多个线程等待多个线程(这里不涉及)。 我们首先来看看怎么实现一个线程等待多个线程吧。 工厂中,对产品需要进行质检,5个工人进行检查,所有...
主要介绍了如何使用CountDownLatch同步java多线程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
这是一个对于Java CountDownLatch的简单Demo CountDownLatch一个同步辅助类 在完成一组正在其他线程中执行的操作之前 它允许一个或多个线程一直等待 用给定的计数 初始化 CountDownLatch 由于调用了 countDown 方法 ...
简介countDownLatch这个类使一个主线程等待其他线程执行完毕后再执行。它是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,
CountDownLatch计数器闭锁是一个能阻塞主线程,让其他线程满足特定条件下主线程再继续执行的线程同步工具。 Latch闭锁的意思,是一种同步的工具类。类似于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭着的,不...
递减锁存器CountDownLatch的使用以及注意事项!
CountDownLatch是一个同步工具类,它通过一个计数器来实现的,初始值为线程的数量。每当一个线程完成了自己的任务,计数器的值就...当计数器到达0时,表示所有的线程都已执行完毕,然后在等待的线程就可以恢复执行任务。
主要介绍了JAVA多线程CountDownLatch的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
它的作用类似于CountDownLatch,可以让一个或多个线程等待其他线程执行完毕后再继续执行。 CyclicBarrier可以被看作是一个屏障,当所有线程都到达这个屏障时,所有线程才能继续执行。与CountDownLatch不同的是,...
《java并发编程》中CountDownLatch和CyclicBarrier用法实例大全,几乎包含了所有重要的用法
例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。 CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会...
CountDownLatch 和 CyclicBarrier 为线程同步的辅助工具,通过它可以做到使一条线程一直阻塞等待,直到其他线程完成其所处理的任务。