`
marb
  • 浏览: 422623 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用 join 或 CountDownLatch 让主线程等待所有子线程完成

    博客分类:
  • JAVA
 
阅读更多

原文出处: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。

 

  1. package com.chenlb;  
  2.   
  3. import java.util.Random;  
  4.   
  5. /** 
  6.  * @author chenlb 2008-11-1 下午11:32:43 
  7.  */  
  8. public class WaitAllSubThread {  
  9.   
  10.     /*int liveThreadNum;//记录运行的子线程数 
  11.     */  
  12.     int n;  //工作线程数  
  13.   
  14.     public WaitAllSubThread(int n) {  
  15.         this.n = n;  
  16.     }  
  17.   
  18.     class Worker implements Runnable {  
  19.   
  20.         String name;  
  21.         int sleep;  
  22.   
  23.         public Worker(String name, int sleep) {  
  24.             this.name = name;  
  25.             this.sleep = sleep;  
  26.         }  
  27.   
  28.         public void run() {  
  29.             /*upLive(); //计算此线程已经工作. 
  30.             */  
  31.             System.out.println(name+", start to work.");  
  32.             try {  
  33.                 Thread.sleep(sleep);    //虚拟工作. 10s 随机时间  
  34.             } catch (InterruptedException e) {  
  35.                 System.out.println(name+" interrupted.");  
  36.             }  
  37.             System.out.println(name+", end to work ["+sleep+"] sleep.");  
  38.             /*downLive();   //此线程工作完成 
  39.             */  
  40.         }  
  41.     }  
  42. /*  //记录线程数的同步方法. 
  43.     private synchronized void downLive() { 
  44.         liveThreadNum--; 
  45.     } 
  46.  
  47.     private synchronized void upLive() { 
  48.         liveThreadNum++; 
  49.     } 
  50.  
  51.     private synchronized boolean isLive() { 
  52.         return liveThreadNum > 0; 
  53.     }*/  
  54.   
  55.     public void run() {  
  56.         System.out.println("-------------main run start-------------");  
  57.         int sleepSaid = 10 * 1000;  //每个工作线程虚拟工作最大时间  
  58.         Random rm = new Random();  
  59.         for(int i=0; i<ths.length; i++) {  
  60.             ths[i] = new Thread(new MyTask(rm.nextInt(sleep)+1));  
  61.   
  62.             ths[i].start();  
  63.         }  
  64.   
  65.         for(Thread th : ths) {  
  66.             try {  
  67.                 th.join();//join方式  
  68.             } catch (InterruptedException e) {  
  69.                 // TODO Auto-generated catch block  
  70.                 e.printStackTrace();  
  71.             }  
  72.         }  
  73.         /*//等待所有工作线程完成. 
  74.         while(isLive()) { 
  75.             try { 
  76.                 Thread.sleep(1000); //每隔1s查看下是否所有线程完成. 
  77.             } catch (InterruptedException e) { 
  78.                 System.out.println("main thread sleep interrupted."); 
  79.             } 
  80.         }*/  
  81.         System.out.println("---------------main run end--------------");  
  82.     }  
  83.   
  84.     public static void main(String[] args) {  
  85.         WaitAllSubThread wast = new WaitAllSubThread(10);  
  86.         wast.run();  
  87.     }  
  88. }  

 

如果不用join,上面的代码会使先输出“main run end”,原因是:main 与 所有sub thread并发工作,不等待所有子线程继续工作。而所有子线程完成了,main线程才会退出。

 

用比较笨的方式:把上面/* */的注释去掉,把 th.join();块注释掉。这样可以使等待所有子线程完成了才去执行其它后续的(比如:这里是输出“main run end”)。分析:程序中加工作的子线程的计数(liveThreadNum)。main不断轮询是否所有子线程完成,所有完成就执行剩下的。

 

上面的是昨天写的,今天发现一个更加简洁的方式去处理main线程阻塞(等待所有子线程),那就是java.util.concurrent.CountDownLatch类。现在重新实现上面的功能,CountDownLatchUse.java。

 

  1. package com.chenlb;  
  2.   
  3. import java.util.Random;  
  4. import java.util.concurrent.CountDownLatch;  
  5.   
  6. /** 
  7.  * @author chenlb 2008-11-1 下午11:43:31 
  8.  */  
  9. public class CountDownLatchUse {  
  10.   
  11.     final CountDownLatch downLatch;  
  12.     int n;  //工作线程数  
  13.   
  14.     public CountDownLatchUse(int n) {  
  15.         this.downLatch = new CountDownLatch(n);  
  16.         this.n = n;  
  17.     }  
  18.   
  19.     class Worker implements Runnable {  
  20.   
  21.         String name;  
  22.         int sleep;  
  23.   
  24.         public Worker(String name, int sleep) {  
  25.             this.name = name;  
  26.             this.sleep = sleep;  
  27.         }  
  28.   
  29.         public void run() {  
  30.             System.out.println(name+", start to work.");  
  31.             try {  
  32.                 Thread.sleep(sleep);    //虚拟工作. 10s 随机时间  
  33.             } catch (InterruptedException e) {  
  34.                 System.out.println(name+" interrupted.");  
  35.             }  
  36.             System.out.println(name+", end to work ["+sleep+"] sleep.");  
  37.             meDone();   //某个工作线程完成  
  38.         }  
  39.     }  
  40.   
  41.     private void meDone() {  
  42.         downLatch.countDown();  
  43.     }  
  44.   
  45.     public void run() {  
  46.         System.out.println("-------------main run start-------------");  
  47.         int sleepSaid = 10 * 1000;  //每个工作线程虚拟工作最大时间  
  48.         Random rm = new Random();  
  49.         for(int i=0; i<n; i++) {  
  50.             new Thread(new Worker("worker-"+i, rm.nextInt(sleepSaid)+1)).start();  
  51.         }  
  52.   
  53.         try {  
  54.             downLatch.await();  //等待所有工作线程完成.  
  55.         } catch (InterruptedException e) {  
  56.             System.out.println("main interrupted.");  
  57.         }  
  58.         System.out.println("---------------main run end--------------");  
  59.     }  
  60.   
  61.     public static void main(String[] args) {  
  62.         CountDownLatchUse mtu = new CountDownLatchUse(10);  
  63.         mtu.run();  
  64.     }  
  65. }  

CountDownLatch.countDown();完成线程的计数。CountDownLatch.await();完成了主线程阻塞。简洁就是好,以后就这种方式了。

分享到:
评论

相关推荐

    Java简单实现“主线程等待所有子线程完成再继续”

    有时我们可能需要设计程序,使得主线程在执行过程中能够等待所有子线程完成后再继续执行。这种需求常见于需要同步多个并行任务或者在主任务结束前确保所有子任务已经处理完毕的场景。本文将详细解释如何使用Java实现...

    Java多线程--让主线程等待所有子线程执行完毕

    - **主线程等待机制**:为了使主线程能够等待所有子线程的完成,可以在主线程中使用一个循环检查`runningThreads`列表,直到该列表为空,表明所有子线程都已完成。 **4. 高级同步机制:CountDownLatch** 另一种更...

    Java多线程--等待所有子线程执行完的五种方法.docx

    例如,如果有多个子线程,我们可以在每个子线程执行`join()`,这样主线程会依次等待每个子线程完成。例如: ```java Thread thread1 = new Thread(...); Thread thread2 = new Thread(...); thread1.start(); ...

    Java多线程–让主线程等待所有子线程执行完毕

    在主线程中,使用一个循环等待所有子线程调用`join()`,这样可以确保所有子线程都完成后再继续主线程。 2. 使用`CountDownLatch`:Java并发包`java.util.concurrent`中的`CountDownLatch`类可以用来同步多个线程。...

    让线程按顺序执行8种方法.doc

    通过使用主线程的join()方法,可以让主线程等待其他线程的执行完成后继续执行。 三、使用线程的wait方法 wait()是Object的方法,作用是让当前线程等待其他线程的唤醒。应用场景:当一个线程需要等待其他线程的结果...

    【IT十八掌徐培成】Java基础第08天-02.多线程-join-daemon-同步.zip

    在Java中,主线程(用户线程)是程序执行的入口,而`daemon`线程则是一种后台服务线程,它不阻止JVM的退出。当所有非`daemon`线程结束时,即使还有`daemon`线程在运行,JVM也会终止。通常,`daemon`线程用于执行如...

    线程学习小Test

    在`ThreadDemo06.java`和`ThreadDemo08.java`中,可能会使用`join()`来确保主线程或其他线程在执行后续操作前等待特定线程结束。例如,如果有一个计算密集型的子线程,主程序可能需要等待它完成后再进行输出或处理...

    线程分解详细

    `join()`方法确保主线程等待所有子线程执行完毕后再继续。 在实际的多线程编程中,我们还需要考虑线程安全问题,避免数据竞争和死锁。此外,线程优先级、线程池等也是提高系统性能的重要手段。对于更复杂的场景,还...

    JAVA多线程学习内容

    线程可以通过sleep()方法进入阻塞状态,通过join()方法让主线程等待子线程完成,通过wait()和notify()或notifyAll()方法进行线程间的同步与通信。 Java提供了多种线程控制机制,如synchronized关键字用于实现互斥...

    Java多线程详解(超详细)_狂神说笔记完整版_项目代码_适合小白随课程学习

    - `join()`方法使主线程等待子线程结束。 - `yield()`方法让当前线程暂停,让其他线程有机会执行。 4. **线程同步** - 当多个线程访问共享资源时,需要进行同步控制,防止数据不一致。 - `synchronized`关键字...

    多线程的使用方式总结

    例如,使用`Thread.Join`方法可以让主线程等待子线程完成,`Thread.Interrupt`方法可以中断线程。 8. **死锁和活锁**:当两个或更多线程互相等待对方释放资源时,就会发生死锁。活锁则是线程不断地重试导致无法进行...

    java线程开发教程

    线程可以通过yield()让出当前CPU时间片,join()方法使主线程等待子线程完成,sleep()方法使线程暂停指定时间。 4. **线程同步**: - **synchronized** 关键字用于控制多线程对共享资源的访问,保证同一时刻只有一...

    15道面试常问的Java多线程面试题!.zip

    - 主线程会捕获子线程的未捕获异常,可以通过UncaughtExceptionHandler处理。 14. **Future和Callable接口** - Future接口表示异步计算的结果,可以检查任务是否完成,获取结果,取消任务。 - Callable接口定义...

    java 多线程编程指南

    Java提供了多种控制线程的方法,如start()启动线程,run()执行线程任务,sleep()让线程暂时休眠,join()等待其他线程结束,yield()让当前线程暂停,让其他线程有机会运行,以及设置优先级等。 并发控制是多线程编程...

    笔记-2、线程的并发工具类2

    在处理包含图片和文字的文档时,如果图片加载是异步的(例如从云上获取),可以使用`Future`来获取图片,主线程继续解析文字。这样可以避免因等待图片加载而阻塞整个解析过程,提高程序的响应性。 了解并熟练使用...

    java线程使用教程

    每个进程至少有一个线程,即主线程。 - **Java程序中的线程**:当Java程序启动时,虚拟机会创建一个主线程来执行程序的`main()`方法。此外,JVM还会创建其他线程用于执行内部任务,比如垃圾回收、对象终结等。 - *...

    Java多线程编程总结

    - 使用 `join()` 方法等待其他线程完成后再继续执行。 5. **守护线程** - 守护线程是在JVM中为其他线程提供服务的线程,当所有非守护线程结束时,JVM也会退出。 #### 八、Java线程:线程的同步-同步方法与同步块...

    可重复使用的并行数据结构和算法.docx

    例如,在数据并行编程中的fork/join模式,主线程会启动多个辅助线程,然后等待所有辅助线程完成其工作。 倒计数锁存的实现通常包含一个初始化的计数值和一个同步机制,如事件或锁。在.NET中,可以通过自定义类来...

    java线程 线程学习资料 java线程教程

    - **主线程**: Java程序启动时,JVM创建的初始线程。 - **后台线程**: JVM内部维护的线程,如垃圾回收线程。 - **用户自定义线程**: 用户可以根据需要创建并管理的线程。 #### 四、线程的生命周期 - **新建状态*...

    编程技巧:如何使用线程

    `join()`方法允许一个线程等待另一个线程完成其执行。 线程优先级是Java线程的一个特性,可以通过`setPriority()`方法设置线程的优先级。然而,线程调度器如何处理优先级并不确定,因此依赖于优先级进行线程调度...

Global site tag (gtag.js) - Google Analytics