读书人

用 join 或 CountDownLatch 让主线程等

发布时间: 2013-08-14 14:27:55 作者: rapoo

用 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. import?java.util.Random;????
  3. /**??*?@author?chenlb?2008-11-1?下午11:32:43?
  4. ?*/??public?class?WaitAllSubThread?{??
  5. ??????/*int?liveThreadNum;//记录运行的子线程数?
  6. ????*/??????int?n;??//工作线程数??
  7. ??????public?WaitAllSubThread(int?n)?{??
  8. ????????this.n?=?n;??????}??
  9. ??????class?Worker?implements?Runnable?{??
  10. ??????????String?name;??
  11. ????????int?sleep;????
  12. ????????public?Worker(String?name,?int?sleep)?{??????????????this.name?=?name;??
  13. ????????????this.sleep?=?sleep;??????????}??
  14. ??????????public?void?run()?{??
  15. ????????????/*upLive();?//计算此线程已经工作.?????????????*/??
  16. ????????????System.out.println(name+",?start?to?work.");??????????????try?{??
  17. ????????????????Thread.sleep(sleep);????//虚拟工作.?10s?随机时间??????????????}?catch?(InterruptedException?e)?{??
  18. ????????????????System.out.println(name+"?interrupted.");??????????????}??
  19. ????????????System.out.println(name+",?end?to?work?["+sleep+"]?sleep.");??????????????/*downLive();???//此线程工作完成?
  20. ????????????*/??????????}??
  21. ????}??/*??//记录线程数的同步方法.?
  22. ????private?synchronized?void?downLive()?{?????????liveThreadNum--;?
  23. ????}??
  24. ????private?synchronized?void?upLive()?{?????????liveThreadNum++;?
  25. ????}??
  26. ????private?synchronized?boolean?isLive()?{?????????return?liveThreadNum?>?0;?
  27. ????}*/????
  28. ????public?void?run()?{??????????System.out.println("-------------main?run?start-------------");??
  29. ????????int?sleepSaid?=?10?*?1000;??//每个工作线程虚拟工作最大时间??????????Random?rm?=?new?Random();??
  30. ????????for(int?i=0;?i<ths.length;?i++)?{??????????????ths[i]?=?new?Thread(new?MyTask(rm.nextInt(sleep)+1));??
  31. ??????????????ths[i].start();??
  32. ????????}????
  33. ????????for(Thread?th?:?ths)?{??????????????try?{??
  34. ????????????????th.join();//join方式??????????????}?catch?(InterruptedException?e)?{??
  35. ????????????????//?TODO?Auto-generated?catch?block??????????????????e.printStackTrace();??
  36. ????????????}??????????}??
  37. ????????/*//等待所有工作线程完成.?????????while(isLive())?{?
  38. ????????????try?{?????????????????Thread.sleep(1000);?//每隔1s查看下是否所有线程完成.?
  39. ????????????}?catch?(InterruptedException?e)?{?????????????????System.out.println("main?thread?sleep?interrupted.");?
  40. ????????????}?????????}*/??
  41. ????????System.out.println("---------------main?run?end--------------");??????}??
  42. ??????public?static?void?main(String[]?args)?{??
  43. ????????WaitAllSubThread?wast?=?new?WaitAllSubThread(10);??????????wast.run();??
  44. ????}??}??

?

如果不用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. import?java.util.Random;??import?java.util.concurrent.CountDownLatch;??
  3. ??/**?
  4. ?*?@author?chenlb?2008-11-1?下午11:43:31??*/??
  5. public?class?CountDownLatchUse?{????
  6. ????final?CountDownLatch?downLatch;??????int?n;??//工作线程数??
  7. ??????public?CountDownLatchUse(int?n)?{??
  8. ????????this.downLatch?=?new?CountDownLatch(n);??????????this.n?=?n;??
  9. ????}????
  10. ????class?Worker?implements?Runnable?{????
  11. ????????String?name;??????????int?sleep;??
  12. ??????????public?Worker(String?name,?int?sleep)?{??
  13. ????????????this.name?=?name;??????????????this.sleep?=?sleep;??
  14. ????????}????
  15. ????????public?void?run()?{??????????????System.out.println(name+",?start?to?work.");??
  16. ????????????try?{??????????????????Thread.sleep(sleep);????//虚拟工作.?10s?随机时间??
  17. ????????????}?catch?(InterruptedException?e)?{??????????????????System.out.println(name+"?interrupted.");??
  18. ????????????}??????????????System.out.println(name+",?end?to?work?["+sleep+"]?sleep.");??
  19. ????????????meDone();???//某个工作线程完成??????????}??
  20. ????}????
  21. ????private?void?meDone()?{??????????downLatch.countDown();??
  22. ????}????
  23. ????public?void?run()?{??????????System.out.println("-------------main?run?start-------------");??
  24. ????????int?sleepSaid?=?10?*?1000;??//每个工作线程虚拟工作最大时间??????????Random?rm?=?new?Random();??
  25. ????????for(int?i=0;?i<n;?i++)?{??????????????new?Thread(new?Worker("worker-"+i,?rm.nextInt(sleepSaid)+1)).start();??
  26. ????????}????
  27. ????????try?{??????????????downLatch.await();??//等待所有工作线程完成.??
  28. ????????}?catch?(InterruptedException?e)?{??????????????System.out.println("main?interrupted.");??
  29. ????????}??????????System.out.println("---------------main?run?end--------------");??
  30. ????}????
  31. ????public?static?void?main(String[]?args)?{??????????CountDownLatchUse?mtu?=?new?CountDownLatchUse(10);??
  32. ????????mtu.run();??????}??
  33. }??

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

读书人网 >编程

热点推荐