1.線程基礎知識
進程是應用程序運行時的一個實例,它包含:一個內核對象,Windows 操作系統用他來管理進程;一個地址空間,包含所有程序集可執行代碼和數據以及對線程堆棧和堆的內存分配。進程擁有自己的屬性以及調度優先級,當系統創建一個進程時,會自動創建一個主線程來執行進程地址空間里面的代碼,主線程可以創建多個子線程。進程地址空間中的代碼沒有任何線程執行時,系統就會終止進程和釋放地址空間。每個進程至少有一個或多個線程,每個線程都有自己的一個執行上下文環境即一組 CPU 寄存器和堆棧,多個運行線程都在進程的地址空間中同時執行代碼,系統會采用輪詢的方式為每個線程分配CPU時間片,線程之間就會進行上下文切換。
線程是應用程序執行的最小單元,線程由一個唯一的線程ID進行標識。每個線程都包含:線程內核對象、線程環境塊、用戶模式棧、內核模式棧以及DLL 線程連接和線程分離通知等要素,線程都有內存空間和運行時間上的開銷。每個線程都會分配0~31的調到優先級,Windows 把線程划分7個相對優先級:Idle、Lowest、BelowNormal、Normal、AboveNormal、Highest和Time-Critical。CLR 保留了Idle和 Time-Critical ,在應用程序中只需要關注其他的5個優先級。CLR 把每個線程看着為前台線程或后台線程,進程中所有的前台線程停止運行時,運行的所有后台線程都會被CLR終止。
多線程能夠提升應用程序的性能,改善用戶體驗,執行並發任務等,比如:執行復雜業務邏輯或長時間的計算任務、I/O操作、網絡請求時,使用后台線程處理這些受限制的任務,就不會阻塞主線。
在 C# 中可以使用 System.Threading.Thread 類來創建一個線程,該類有4個重要構造函數,每個構造函數都接受一個線程啟動時需要執行的函數(委托)以及線程的最大堆棧大小。
public Thread(ParameterizedThreadStart start); public Thread(ThreadStart start); public Thread(ParameterizedThreadStart start, int maxStackSize); public Thread(ThreadStart start, int maxStackSize);
參數委托定義:
public delegate void ThreadStart(); public delegate void ParameterizedThreadStart(object obj); ParameterizedThreadStart 委托允許線程啟動時為執行方法傳遞一個需要使用的數據對象。
使用 Thread 類創建一個線程並執行任務,創建一個線程可以為線程制定線程的名稱、優先級、是否為后台線程以及設置線程的區域性等屬性。
1: private static void CreateThread()
2: {
3: //創建一個線程,可以構造 System.Threading.ParameterizedThreadStart 委托或 System.Threading.ThreadStart 委托實例
4: Thread thread = new Thread(state =>
5: {
6: //線程啟動時需要執行的任務
7: int sum = 0;
8: //將當前線程掛起指定的時間,這兒是2000毫秒
9: Thread.Sleep(2000);
10: for (int i = 0; i < 1000; i++)
11: {
12: sum++;
13: }
14: Console.WriteLine("計數值:{0}", sum.ToString());
15: });
16: thread.Name = "執行長時間的計算處理";//設置線程的名稱
17: thread.Priority = ThreadPriority.AboveNormal;//設置線程優先級
18: thread.CurrentCulture = new System.Globalization.CultureInfo("EN");//設置線程區域性
19: Thread thread2 = new Thread(() => {
20: Thread.Sleep(2000);
21: Console.WriteLine("執行復雜任務");
22: });
23: //啟動線程,可以傳遞一個線程執行方法所使用的數據對象
24: thread.Start(null);
25: thread2.Start();
26: }
3.Thread 類的一些重要的方法和屬性
Thread.Sleep 靜態方法將當前線程掛起指定的時間,可以接受一個Int類型的表示掛起線程的毫秒數或TimeSpan類型的時間值。
1: static void Main(string[] args)
2: {
3: Thread t = new Thread(new ThreadStart(() => {
4: Console.WriteLine("當前線程將會被阻塞1秒鍾。");
5: Thread.Sleep(1000);
6: Console.WriteLine("當前線程被阻塞1秒以后繼續執行。");
7: }));
8: t.Start();
9: Console.WriteLine("主線程執行任務。");
10: }
子線程會被阻塞1秒鍾。
Join 方法會阻塞調用線程,直到某個線程終止或經過了指定時間為止。
1: static void Main(string[] args)
2: {
3: Console.WriteLine("主線程開始執行任務。");
4: Thread t = new Thread(new ThreadStart(() => {
5: Console.WriteLine("子線程執行任務,並阻塞調用線程。");
6:
7: }));
8: t.Start();
9: //調用線程被阻塞2000毫秒
10: t.Join(2000);
11: Console.WriteLine("主線程被阻塞后繼續執行任務。");
12: }
Interrupt 方法中斷處於 WaitSleepJoin 線程狀態的線程,可以通過線程的 ThreadState 屬性獲得當前線程的狀態,每個線程都具有如下的狀態:
1: public enum ThreadState
2: {
3: Running = 0,
4: StopRequested = 1,
5: SuspendRequested = 2,
6: Background = 4,
7: Unstarted = 8,
8: Stopped = 16,
9: WaitSleepJoin = 32,
10: Suspended = 64,
11: AbortRequested = 128,
12: Aborted = 256,
13: }
程序示例:
1: static void Main(string[] args)
2: {
3: Console.WriteLine("主線程開始執行任務。");
4: Thread t = null;
5: t= new Thread(new ThreadStart(() => {
6: Thread.Sleep(2000);
7: Console.WriteLine("子線程執行任務。");
8: }));
9: Console.WriteLine("調用Start方法前子線程的狀態:{0}",t.ThreadState.ToString());
10: t.Start();
11: Console.WriteLine("調用Start方法后子線程當前狀態:{0}", t.ThreadState.ToString());
12: //調用線程被阻塞2000毫秒
13: t.Join(2000);
14: Console.WriteLine("調用Join方法后子線程的狀態:{0}", t.ThreadState.ToString());
15: Thread.Sleep(1000);
16: //終止處於 WaitSleepJoin 狀態的的線程。
17: t.Interrupt();
18: Console.WriteLine("調用Interrupt方法后子線程的狀態:{0}", t.ThreadState.ToString());
19: Console.WriteLine("主線程被阻塞后繼續執行任務。");
20: }
Abort 方法在調用此方法的線程上引發 System.Threading.ThreadAbortException 異常,以開始終止此線程的過程。
1: static void Main(string[] args)
2: {
3: Thread t = null;
4: t = new Thread(() =>
5: {
6: try
7: {
8: Thread.Sleep(1000);
9: Console.WriteLine("子線程執行任務。");
10: }
11: catch
12: {
13: Console.WriteLine("子線程引發終止異常,線程狀態:{0}。", Thread.CurrentThread.ThreadState.ToString());
14: }
15: finally
16: {
17: Console.WriteLine("進入finally塊語句子線程狀態:{0}。", Thread.CurrentThread.ThreadState.ToString());
18: }
19: });
20: t.Start();
21: Thread.Sleep(1000);
22: //終止子線程
23: t.Abort();
24: t.Join();
25: Console.WriteLine("子線程線程狀態:{0}。", t.ThreadState.ToString());
26: }
Suspend 方法掛起線程和Resume 繼續已掛起的線程,這兩個方法已經過時。
線程的重要屬性:
Thread.CurrentContext 靜態屬性獲取線程正在其中執行的當前上下文。
Thread.CurrentThread 靜態屬性獲取當前正在運行的線程。
Name 獲取或設置線程的名稱。
IsAlive 獲取當期線程的執行狀態。
IsBackground 獲取或設置線程是否為后台線程。
IsThreadPoolThread 指示一個線程是否屬於托管線程池線程。
ManagedThreadId 獲取當前線程的唯一標識符。
Priority 獲取或設置線程的調度優先級。
ThreadState 獲取當前線程的狀態。
關於線程的具體詳情參見MSDN對 System.Threading.Thread 類的描述。
本文只是簡單的介紹了線程的基礎知識以及使用和一些方法屬性,需要在具體業務中實踐,合理使用線程這種寶貴的資源以提升應用程序性能。