五、 判斷多個線程是否都結束的兩種方法
確定所有線程是否都完成了工作的方法有很多,如可以採用類似於對象計數器的方法,所謂對象計數器,就是一個對象被引用一次,這個計數器就加1,銷燬引用就減1,如果引用數爲0,則垃圾蒐集器就會對這些引用數爲0的對象進行回收。
方法一:線程計數器
線程也可以採用計數器的方法,即爲所有需要監視的線程設一個線程計數器,每開始一個線程,在線程的執行方法中爲這個計數器加1,如果某個線程結束(在線程執行方法的最後爲這個計數器減1),爲這個計數器減1。然後再開始一個線程,按着一定的時間間隔來監視這個計數器,如是棕個計數器爲0,說明所有的線程都結束了。當然,也可以不用這個監視線程,而在每一個工作線程的最後(在爲計數器減1的代碼的後面)來監視這個計數器,也就是說,每一個工作線程在退出之前,還要負責檢測這個計數器。使用這種方法不要忘了同步這個計數器變量啊,否則會產生意想不到的後果。
方法二:使用Thread.join方法
join方法只有在線程結束時才繼續執行下面的語句。可以對每一個線程調用它的join方法,但要注意,這個調用要在另一個線程裏,而不要在主線程,否則程序會被阻塞的。
個人感覺這種方法比較好。
線程計數器方法演示:{
private static int count = 0;
private int ms;
private static void increment()
{
lock (typeof(ThreadCounter)) // 必須同步計數器
{
count++;
}
}
private static void decrease()
{
lock (typeof(ThreadCounter))
{
count--;
}
}
private static int getCount()
{
lock (typeof(ThreadCounter))
{
return count;
}
}
public ThreadCounter(int ms)
{
this.ms = ms;
}
override public void run()
{
increment();
Thread.Sleep(ms);
Console.WriteLine(ms.ToString()+"毫秒任務結束");
decrease();
if (getCount() == 0)
Console.WriteLine("所有任務結束");
}
}
ThreadCounter counter1 = new ThreadCounter(3000);
ThreadCounter counter2 = new ThreadCounter(5000);
ThreadCounter counter3 = new ThreadCounter(7000);
counter1.start();
counter2.start();
counter3.start();
上面的代碼雖然在大多數的時候可以正常工作,但卻存在一個隱患,就是如果某個線程,假設是counter1,在運行後,由於某些原因,其他的線程並未運行,在這種情況下,在counter1運行完後,仍然可以顯示出“所有任務結束”的提示信息,但是counter2和counter3還並未運行。爲了消除這個隱患,可以將increment方法從run中移除,將其放到ThreadCounter的構造方法中,在這時,increment方法中的lock也可以去掉了。代碼如:
public ThreadCounter(int ms)
{
this.ms = ms;
increment();
}
運行上面的程序後,將顯示如圖2的結果。
圖2
使用Thread.join方法演示
{
Thread.Sleep(Int32.Parse(obj.ToString()));
Console.WriteLine(obj + "毫秒任務結束");
}
private static void joinAllThread(object obj)
{
Thread[] threads = obj as Thread[];
foreach (Thread t in threads)
t.Join();
Console.WriteLine("所有的線程結束");
}
static void Main(string[] args)
{
Thread thread1 = new Thread(threadMethod);
Thread thread2 = new Thread(threadMethod);
Thread thread3 = new Thread(threadMethod);
thread1.Start(3000);
thread2.Start(5000);
thread3.Start(7000);
Thread joinThread = new Thread(joinAllThread);
joinThread.Start(new Thread[] { thread1, thread2, thread3 });
}
在運行上面的代碼後,將會得到和圖2同樣的運行結果。上述兩種方法都沒有線程數的限制,當然,仍然會受到操作系統和硬件資源的限制。