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

原文出处: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();完成了主线程阻塞。简洁就是好,以后就这种方式了。 8)

发布了430 篇原创文章 · 获赞 415 · 访问量 925万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览