背景
本文是為了回復博客園一個兄弟的問題,主要回答兩個問題:
- 如何讓線程支持超時?
- 如何讓線程在執行結束后銷毀?
MS 現在不推薦使用低級別的 Thread 編程,而推薦使用 Task,另外我多數情況都是做企業應用,很少需要多線程編程的場景,本文中的知識都是從 《clr via c#》學習而來。
如何讓線程支持超時?
使用 CancellationTokenSource
代碼
1 private static void TimeoutTest1() 2 { 3 var cts = new CancellationTokenSource(); 4 5 var thread = new Thread(() => 6 { 7 Console.WriteLine(String.Format("線程{0}執行中", Thread.CurrentThread.ManagedThreadId)); 8 Thread.Sleep(10000); 9 Console.WriteLine(String.Format("線程{0}執行中", Thread.CurrentThread.ManagedThreadId)); 10 }); 11 12 cts.Token.Register(() => 13 { 14 thread.Abort(); 15 }); 16 cts.CancelAfter(1000); 17 18 thread.Start(); 19 thread.Join(); 20 21 Console.WriteLine(String.Format("線程{0}的狀態:{1}", thread.ManagedThreadId, thread.ThreadState)); 22 }
輸出
備注
這里采用了 Abort 終止了線程,CancellationTokenSource 也支持其它模式,可以去官方看看文檔。
使用 Join
代碼
1 private static void TimeoutTest2() 2 { 3 var thread = new Thread(() => 4 { 5 Console.WriteLine(String.Format("線程{0}執行中", Thread.CurrentThread.ManagedThreadId)); 6 Thread.Sleep(10000); 7 Console.WriteLine(String.Format("線程{0}執行中", Thread.CurrentThread.ManagedThreadId)); 8 }); 9 10 thread.Start(); 11 thread.Join(1000); 12 thread.Abort(); 13 14 Console.WriteLine(String.Format("線程{0}的狀態:{1}", thread.ManagedThreadId, thread.ThreadState)); 15 }
輸出
基於 Task 的實現
代碼
1 private static void TimeoutTest3() 2 { 3 var cts = new CancellationTokenSource(); 4 var task = new Task(() => 5 { 6 while (true) 7 { 8 cts.Token.ThrowIfCancellationRequested(); 9 10 Console.WriteLine("xxxxxx"); 11 Thread.Sleep(1000); 12 } 13 }, cts.Token); 14 15 task.Start(); 16 17 cts.CancelAfter(5000); 18 19 Console.ReadLine(); 20 }
輸出
如何讓線程在執行結束后銷毀?
線程執行完、遇到未處理異常和被終止后就自動不可用了,如果是垃圾,自然會被 GC 給回收,有一點需要說明的是:線程的未處理異常會導致應用程序的終止,一個線程的異常不會自動冒泡到其它線程。
備注
我學習多線程知識感覺到的一個好處就是:讓我對數據庫並發有了更深刻的認識了,找個機會寫寫線程的樂觀鎖和數據庫的樂觀鎖的比較,思路基本一樣。