有時候我們會遇到這樣的問題:做一個大的事情可以被分解為做一系列相似的小的事情,而小的事情無非就是參數上有可能不相同而已!
此時,如果不使用線程,我們勢必會浪費非常多的時間來完成整個大的事情,而使用線程的話將會存在這樣的問題:
主線程啟動所有子線程並發執行後主線程就直接返回了,導致外部函數判讀整個大的事情完成了,但是實際上並沒有完成!
針對以上情況我想我會采用多線程方式執行同時解決主線程等待子線程的問題。如圖:
在這裡我使用Java進行案例分析。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+ytfPyL2owaLSu7j2z9+zzLncwO3A4KOs08PT2sb0tq/L+dPQ19PP37PMus21yLT9y/nT0NfTz9+zzM3qs8mjrNTa1eLA77K7yrnTw9Ddw9/Su7bOyrG85Lrz0a27t7zssuK1xLe9yr2jqM/7usRDVVDNrMqxz/u6xMqxvOSjrMirsr/N6rPJyrG85LK7ubu8sMqxtcjIsbXjo6mju7b4ysfKudPDtci0/cHZvecmIzIwNTQwO7XEt73KvaGjVGhyZWFkTWFuYWdlci5qYXZhyOfPwqO6PC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">public class ThreadManager implements NotifyInterface {
private final Object mLock = new Object();
private int mCount = 0;
private int endCount = 0;
public ThreadManager(int count) {
System.out.println("Manager In.");
this.mCount = count;
this.addThread();
synchronized (mLock) {
while (true) {
if (checkEnd())
break;
try {
mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Manager Out.");
}
private void addThread() {
System.out.println("Manager addThread().");
for (int i = 1; i <= mCount; i++) {
ThreadDoThing dThread = new ThreadDoThing(i, "T" + i, this);
// Start
dThread.start();
}
}
private boolean checkEnd() {
boolean bFlag = false;
bFlag = endCount >= mCount;
System.out.println("Manager checkEnd().Return is:" + bFlag);
return bFlag;
}
@Override
public void runEnd() {
synchronized (mLock) {
++endCount;
mLock.notifyAll();
}
}
}
此類集成自:NotifyInterface接口,NotifyInterface是用於子線程通知主線程自己已經完成工作所用類,ThreadManager實例化時將傳入一個int值,用於設置啟動的子線程數,當然這裡是為了簡單介紹所以采用的這樣的方式,實際情況可能更加復雜。
在實例化後 進入構造方法,此時將會啟動子線程,啟動後進入循環等待中,當檢測到所有子線程完成時就退出循環,沒有就將進入臨界值等待,直到通過接口通知主線程完成時將會通知臨界值一次,此時循環將會執行一次,如果不滿足退出條件將繼續等待臨界值。直到滿足為止。
NotifyInterface接口如下:
public interface NotifyInterface { public abstract void runEnd(); }
public class ThreadDoThing extends Thread { private NotifyInterface mInterface = null; private int mId = 0; private String mArgs = null; public ThreadDoThing(int id, String args, NotifyInterface iface) { this.mId = id; this.mArgs = args; this.AddInterface(iface); } public void AddInterface(NotifyInterface iface) { this.mInterface = iface; } @Override public void run() { System.out.println("ThreadDoThing Id is:" + this.mId + " Args is:" + this.mArgs); System.out.println(this.mId + ":Doing..."); int sleepTime = (int) (Math.random() * 1000); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.mId + ":SleepTime is:" + sleepTime); this.notifyEnd(); System.out.println(this.mId + ":Do End."); } private void notifyEnd() { if (this.mInterface != null) this.mInterface.runEnd(); System.out.println(this.mId + ":Notify End."); } }
在工作中,我使用了隨機一個1s內的休眠來代替所做工作的時間,完成後調用接口通知完成。
測試方法如下:
/** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ThreadManager manager = new ThreadManager(10); }
Manager In. Manager addThread(). ThreadDoThing Id is:1 Args is:T1 ThreadDoThing Id is:2 Args is:T2 2:Doing... 1:Doing... ThreadDoThing Id is:3 Args is:T3 ThreadDoThing Id is:4 Args is:T4 3:Doing... 4:Doing... ThreadDoThing Id is:5 Args is:T5 5:Doing... ThreadDoThing Id is:6 Args is:T6 Manager checkEnd().Return is:false ThreadDoThing Id is:8 Args is:T8 ThreadDoThing Id is:7 Args is:T7 8:Doing... ThreadDoThing Id is:9 Args is:T9 9:Doing... 6:Doing... ThreadDoThing Id is:10 Args is:T10 7:Doing... 10:Doing... 3:SleepTime is:111 3:Notify End. 3:Do End. Manager checkEnd().Return is:false 5:SleepTime is:142 5:Notify End. Manager checkEnd().Return is:false 5:Do End. 4:SleepTime is:199 4:Notify End. Manager checkEnd().Return is:false 4:Do End. 7:SleepTime is:342 7:Notify End. Manager checkEnd().Return is:false 7:Do End. 10:SleepTime is:346 10:Notify End. Manager checkEnd().Return is:false 10:Do End. 6:SleepTime is:397 6:Notify End. Manager checkEnd().Return is:false 6:Do End. 9:SleepTime is:468 9:Notify End. Manager checkEnd().Return is:false 9:Do End. 1:SleepTime is:475 1:Notify End. Manager checkEnd().Return is:false 1:Do End. 2:SleepTime is:686 Manager checkEnd().Return is:false 2:Notify End. 2:Do End. 8:SleepTime is:828 8:Notify End. Manager checkEnd().Return is:true 8:Do End. Manager Out.
具體情況大家可以衍生考慮,檢測是否全部返回也可以有多種方式甚至設置添加一個定時器之類的。
以後有時間畫一個詳細點的圖!