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

本文介绍了在Java中如何使用join方法及CountDownLatch类实现主线程等待所有子线程完成的操作。通过具体示例代码展示了不同同步机制的应用场景及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文出处: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. packagecom.chenlb;
  2. importjava.util.Random;
  3. /**
  4. *@authorchenlb2008-11-1下午11:32:43
  5. */
  6. publicclassWaitAllSubThread{
  7. /*intliveThreadNum;//记录运行的子线程数
  8. */
  9. intn;//工作线程数
  10. publicWaitAllSubThread(intn){
  11. this.n=n;
  12. }
  13. classWorkerimplementsRunnable{
  14. Stringname;
  15. intsleep;
  16. publicWorker(Stringname,intsleep){
  17. this.name=name;
  18. this.sleep=sleep;
  19. }
  20. publicvoidrun(){
  21. /*upLive();//计算此线程已经工作.
  22. */
  23. System.out.println(name+",starttowork.");
  24. try{
  25. Thread.sleep(sleep);//虚拟工作.10s随机时间
  26. }catch(InterruptedExceptione){
  27. System.out.println(name+"interrupted.");
  28. }
  29. System.out.println(name+",endtowork["+sleep+"]sleep.");
  30. /*downLive();//此线程工作完成
  31. */
  32. }
  33. }
  34. /*//记录线程数的同步方法.
  35. privatesynchronizedvoiddownLive(){
  36. liveThreadNum--;
  37. }
  38. privatesynchronizedvoidupLive(){
  39. liveThreadNum++;
  40. }
  41. privatesynchronizedbooleanisLive(){
  42. returnliveThreadNum>0;
  43. }*/
  44. publicvoidrun(){
  45. System.out.println("-------------mainrunstart-------------");
  46. intsleepSaid=10*1000;//每个工作线程虚拟工作最大时间
  47. Randomrm=newRandom();
  48. for(inti=0;i<ths.length;i++){
  49. ths[i]=newThread(newMyTask(rm.nextInt(sleep)+1));
  50. ths[i].start();
  51. }
  52. for(Threadth:ths){
  53. try{
  54. th.join();//join方式
  55. }catch(InterruptedExceptione){
  56. //TODOAuto-generatedcatchblock
  57. e.printStackTrace();
  58. }
  59. }
  60. /*//等待所有工作线程完成.
  61. while(isLive()){
  62. try{
  63. Thread.sleep(1000);//每隔1s查看下是否所有线程完成.
  64. }catch(InterruptedExceptione){
  65. System.out.println("mainthreadsleepinterrupted.");
  66. }
  67. }*/
  68. System.out.println("---------------mainrunend--------------");
  69. }
  70. publicstaticvoidmain(String[]args){
  71. WaitAllSubThreadwast=newWaitAllSubThread(10);
  72. wast.run();
  73. }
  74. }

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

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

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

  1. packagecom.chenlb;
  2. importjava.util.Random;
  3. importjava.util.concurrent.CountDownLatch;
  4. /**
  5. *@authorchenlb2008-11-1下午11:43:31
  6. */
  7. publicclassCountDownLatchUse{
  8. finalCountDownLatchdownLatch;
  9. intn;//工作线程数
  10. publicCountDownLatchUse(intn){
  11. this.downLatch=newCountDownLatch(n);
  12. this.n=n;
  13. }
  14. classWorkerimplementsRunnable{
  15. Stringname;
  16. intsleep;
  17. publicWorker(Stringname,intsleep){
  18. this.name=name;
  19. this.sleep=sleep;
  20. }
  21. publicvoidrun(){
  22. System.out.println(name+",starttowork.");
  23. try{
  24. Thread.sleep(sleep);//虚拟工作.10s随机时间
  25. }catch(InterruptedExceptione){
  26. System.out.println(name+"interrupted.");
  27. }
  28. System.out.println(name+",endtowork["+sleep+"]sleep.");
  29. meDone();//某个工作线程完成
  30. }
  31. }
  32. privatevoidmeDone(){
  33. downLatch.countDown();
  34. }
  35. publicvoidrun(){
  36. System.out.println("-------------mainrunstart-------------");
  37. intsleepSaid=10*1000;//每个工作线程虚拟工作最大时间
  38. Randomrm=newRandom();
  39. for(inti=0;i<n;i++){
  40. newThread(newWorker("worker-"+i,rm.nextInt(sleepSaid)+1)).start();
  41. }
  42. try{
  43. downLatch.await();//等待所有工作线程完成.
  44. }catch(InterruptedExceptione){
  45. System.out.println("maininterrupted.");
  46. }
  47. System.out.println("---------------mainrunend--------------");
  48. }
  49. publicstaticvoidmain(String[]args){
  50. CountDownLatchUsemtu=newCountDownLatchUse(10);
  51. mtu.run();
  52. }
  53. }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值