多线程同步-主线程等待所有子线程完成案例

http://blog.csdn.net/qiujuer/article/details/34862469

有时候我们会遇到这样的问题:做一个大的事情可以被分解为做一系列相似的小的事情,而小的事情无非就是参数上有可能不相同而已!

此时,如果不使用线程,我们势必会浪费非常多的时间来完成整个大的事情,而使用线程的话将会存在这样的问题:

主线程启动所有子线程并发执行后主线程就直接返回了,导致外部函数判读整个大的事情完成了,但是实际上并没有完成!


针对以上情况我想我会采用多线程方式执行同时解决主线程等待子线程的问题。如图:

多线程同步-主线程等待所有子线程完成案例_第1张图片

在这里我使用Java进行案例分析。

首先建立一个线程管理类,用于启动所有子线程和等待所有子线程完成,在这里不使用休眠一段时间后循环检测的方式(消耗CUP同时消耗时间,全部完成时间不够及时等缺点);而是使用等待临界值的方式。ThreadManager.java如下:

[java]  view plain copy
  1. public class ThreadManager implements NotifyInterface {  
  2.     private final Object mLock = new Object();  
  3.     private int mCount = 0;  
  4.     private int endCount = 0;  
  5.   
  6.     public ThreadManager(int count) {  
  7.         System.out.println("Manager In.");  
  8.   
  9.         this.mCount = count;  
  10.   
  11.         this.addThread();  
  12.   
  13.         synchronized (mLock) {  
  14.             while (true) {  
  15.                 if (checkEnd())  
  16.                     break;  
  17.                 try {  
  18.                     mLock.wait();  
  19.                 } catch (InterruptedException e) {  
  20.                     e.printStackTrace();  
  21.                 }  
  22.             }  
  23.         }  
  24.   
  25.         System.out.println("Manager Out.");  
  26.     }  
  27.   
  28.     private void addThread() {  
  29.         System.out.println("Manager addThread().");  
  30.   
  31.         for (int i = 1; i <= mCount; i++) {  
  32.             ThreadDoThing dThread = new ThreadDoThing(i, "T" + i, this);  
  33.             // Start  
  34.             dThread.start();  
  35.         }  
  36.   
  37.     }  
  38.   
  39.     private boolean checkEnd() {  
  40.         boolean bFlag = false;  
  41.         bFlag = endCount >= mCount;  
  42.   
  43.         System.out.println("Manager checkEnd().Return is:" + bFlag);  
  44.   
  45.         return bFlag;  
  46.     }  
  47.   
  48.     @Override  
  49.     public void runEnd() {  
  50.         synchronized (mLock) {  
  51.             ++endCount;  
  52.   
  53.             mLock.notifyAll();  
  54.         }  
  55.     }  
  56. }  

此类集成自:NotifyInterface接口,NotifyInterface是用于子线程通知主线程自己已经完成工作所用类,ThreadManager实例化时将传入一个int值,用于设置启动的子线程数,当然这里是为了简单介绍所以采用的这样的方式,实际情况可能更加复杂。

在实例化后  进入构造方法,此时将会启动子线程,启动后进入循环等待中,当检测到所有子线程完成时就退出循环,没有就将进入临界值等待,直到通过接口通知主线程完成时将会通知临界值一次,此时循环将会执行一次,如果不满足退出条件将继续等待临界值。直到满足为止。

NotifyInterface接口如下:

[java]  view plain copy
  1. public interface NotifyInterface {  
  2.       
  3.     public abstract void runEnd();  
  4.   
  5. }  

测试用的子线程ThreadDoThing.java如下:

[java]  view plain copy
  1. public class ThreadDoThing extends Thread {  
  2.     private NotifyInterface mInterface = null;  
  3.     private int mId = 0;  
  4.     private String mArgs = null;  
  5.   
  6.     public ThreadDoThing(int id, String args, NotifyInterface iface) {  
  7.         this.mId = id;  
  8.         this.mArgs = args;  
  9.         this.AddInterface(iface);  
  10.     }  
  11.   
  12.     public void AddInterface(NotifyInterface iface) {  
  13.         this.mInterface = iface;  
  14.     }  
  15.   
  16.     @Override  
  17.     public void run() {  
  18.         System.out.println("ThreadDoThing Id is:" + this.mId + " Args is:" + this.mArgs);  
  19.         System.out.println(this.mId + ":Doing...");  
  20.   
  21.         int sleepTime = (int) (Math.random() * 1000);  
  22.   
  23.         try {  
  24.             Thread.sleep(sleepTime);  
  25.         } catch (InterruptedException e) {  
  26.             e.printStackTrace();  
  27.         }  
  28.         System.out.println(this.mId + ":SleepTime is:" + sleepTime);  
  29.   
  30.         this.notifyEnd();  
  31.   
  32.         System.out.println(this.mId + ":Do End.");  
  33.     }  
  34.   
  35.     private void notifyEnd() {  
  36.         if (this.mInterface != null)  
  37.             this.mInterface.runEnd();  
  38.   
  39.         System.out.println(this.mId + ":Notify End.");  
  40.     }  
  41. }  

此类继承自Thread类,可直接重写Run()方法完成所做工作!

在工作中,我使用了随机一个1s内的休眠来代替所做工作的时间,完成后调用接口通知完成。


测试方法如下:

[java]  view plain copy
  1. /** 
  2.  * @param args 
  3.  */  
  4. public static void main(String[] args) {  
  5.     // TODO Auto-generated method stub  
  6.     ThreadManager manager = new ThreadManager(10);  
  7. }  

测试结果:

[plain]  view plain copy
  1. Manager In.  
  2. Manager addThread().  
  3. ThreadDoThing Id is:1 Args is:T1  
  4. ThreadDoThing Id is:2 Args is:T2  
  5. 2:Doing...  
  6. 1:Doing...  
  7. ThreadDoThing Id is:3 Args is:T3  
  8. ThreadDoThing Id is:4 Args is:T4  
  9. 3:Doing...  
  10. 4:Doing...  
  11. ThreadDoThing Id is:5 Args is:T5  
  12. 5:Doing...  
  13. ThreadDoThing Id is:6 Args is:T6  
  14. Manager checkEnd().Return is:false  
  15. ThreadDoThing Id is:8 Args is:T8  
  16. ThreadDoThing Id is:7 Args is:T7  
  17. 8:Doing...  
  18. ThreadDoThing Id is:9 Args is:T9  
  19. 9:Doing...  
  20. 6:Doing...  
  21. ThreadDoThing Id is:10 Args is:T10  
  22. 7:Doing...  
  23. 10:Doing...  
  24. 3:SleepTime is:111  
  25. 3:Notify End.  
  26. 3:Do End.  
  27. Manager checkEnd().Return is:false  
  28. 5:SleepTime is:142  
  29. 5:Notify End.  
  30. Manager checkEnd().Return is:false  
  31. 5:Do End.  
  32. 4:SleepTime is:199  
  33. 4:Notify End.  
  34. Manager checkEnd().Return is:false  
  35. 4:Do End.  
  36. 7:SleepTime is:342  
  37. 7:Notify End.  
  38. Manager checkEnd().Return is:false  
  39. 7:Do End.  
  40. 10:SleepTime is:346  
  41. 10:Notify End.  
  42. Manager checkEnd().Return is:false  
  43. 10:Do End.  
  44. 6:SleepTime is:397  
  45. 6:Notify End.  
  46. Manager checkEnd().Return is:false  
  47. 6:Do End.  
  48. 9:SleepTime is:468  
  49. 9:Notify End.  
  50. Manager checkEnd().Return is:false  
  51. 9:Do End.  
  52. 1:SleepTime is:475  
  53. 1:Notify End.  
  54. Manager checkEnd().Return is:false  
  55. 1:Do End.  
  56. 2:SleepTime is:686  
  57. Manager checkEnd().Return is:false  
  58. 2:Notify End.  
  59. 2:Do End.  
  60. 8:SleepTime is:828  
  61. 8:Notify End.  
  62. Manager checkEnd().Return is:true  
  63. 8:Do End.  
  64. Manager Out.  

实际情况可能更加复杂,甚至子线程下还有更多的子线程!

具体情况大家可以衍生考虑,检测是否全部返回也可以有多种方式甚至设置添加一个定时器之类的。

以后有时间画一个详细点的图!


你可能感兴趣的:(多线程同步-主线程等待所有子线程完成案例)