有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已!
此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情。而使用线程的话将会存在这种问题:
主线程启动全部子线程并发运行后主线程就直接返回了,导致外部函数判读整个大的事情完毕了,可是实际上并没有完毕!
针对以上情况我想我会採用多线程方式运行同一时候解决主线程等待子线程的问题。如图:
在这里我使用Java进行案例分析。
首先建立一个线程管理类。用于启动全部子线程和等待全部子线程完毕。在这里不使用休眠一段时间后循环检測的方式(消耗CUP同一时候消耗时间,全部完毕时间不够及时等缺点)。而是使用等待临界值的方式。
ThreadManager.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();
}
測试用的子线程ThreadDoThing.java例如以下:
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.");
}
}
此类继承自Thread类,可直接重写Run()方法完毕所做工作。
在工作中,我使用了随机一个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.
实际情况可能更加复杂。甚至子线程下还有很多其它的子线程!
详细情况大家能够衍生考虑,检測是否所有返回也能够有多种方式甚至设置加入一个定时器之类的。
以后有时间画一个具体点的图!