System.Threading.Thread 是 .NET 中**手動建立與控制執行緒**的核心類別。雖然現代開發推薦使用 Task、ThreadPool、async/await 等高階抽象,但理解 Thread 的生命週期、狀態機制、優先級、同步方法 (Join、Sleep、Abort、Interrupt) 仍是掌握多執行緒本質、除錯複雜並發問題、維護舊版程式碼的必要基礎。本文將完整解析 Thread 的建立方式、ThreadStart 委派、啟動與終止流程、主執行緒關係、ThreadState 狀態列舉、優先級設定,並提供完整可執行範例。
Thread 建構函式接受 ThreadStart 委派 (無參數、無回傳值) 或 ParameterizedThreadStart (單一 object 參數):
// 無參數版本
public delegate void ThreadStart();
// 有參數版本 (需轉型)
public delegate void ParameterizedThreadStart(object obj);
using System;
using System.Threading;
namespace ThreadBasicDemo
{
class Worker
{
public void DoWork()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"[Worker] 執行中... {i} (ThreadId: {Thread.CurrentThread.ManagedThreadId})");
Thread.Sleep(500);
}
}
}
class Program
{
static void Main()
{
Console.WriteLine($"[Main] 主執行緒啟動 (ThreadId: {Thread.CurrentThread.ManagedThreadId})");
var worker = new Worker();
// 1. 建立執行緒,指定入口方法
Thread t = new Thread(worker.DoWork); // 隱含轉換為 ThreadStart
// 2. 設定執行緒屬性 (可選)
t.Name = "MyWorkerThread";
t.IsBackground = false; // 前景執行緒:會阻止程式結束
// 3. 啟動執行緒
t.Start();
// 4. 主執行緒等待子執行緒啟動 (確保 IsAlive 為 true)
while (!t.IsAlive) Thread.Sleep(1);
Console.WriteLine($"[Main] 子執行緒已啟動,狀態: {t.ThreadState}");
// 5. 等待子執行緒結束 (Join)
t.Join(); // 無限期等待;也可 t.Join(TimeSpan) 設定逾時
Console.WriteLine("[Main] 子執行緒已結束,主執行緒繼續。");
Console.ReadKey();
}
}
}
| 方法 | 機制 | 特點 | 建議 |
|---|---|---|---|
| 自然結束 | 入口方法執行完畢返回 | 最安全、資源正常釋放、finally 區塊執行 | 首選:設計可結束的迴圈條件 (如 CancellationToken、volatile bool 旗標) |
Abort() | 擲出 ThreadAbortException 強制中止 | 已淘汰 (.NET Core 不支援)、不可預測、可能損毀資料、finally 仍執行但 ResetAbort 可阻止 | 嚴禁使用,舊版相容性除外 |
Interrupt() | 在執行緒處於 WaitSleepJoin 狀態時擲出 ThreadInterruptedException | 僅能中斷阻塞中執行緒 (Sleep、Join、Wait);執行中程式碼不受影響 | 輔助手段,配合 try-catch 處理 |
var cts = new CancellationTokenSource();
Thread t = new Thread(() => DoWork(cts.Token));
t.Start();
// ... 某時刻要求取消
cts.Cancel(); // 發出取消信號
void DoWork(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
// 工作邏輯
token.ThrowIfCancellationRequested(); // 或手動檢查 token.IsCancellationRequested
}
}
t.Join():無限期阻塞呼叫執行緒,直到 t 結束。t.Join(TimeSpan timeout) / t.Join(int millisecondsTimeout):等待指定時間,逾時回傳 false,執行緒仍在執行回傳 true。Join 執行緒 B,而 B 又嘗試 Join A 或鎖定 A 持有的資源,將發生死結。ThreadState 為 Flags 屬性 (可組合),常見值:
| 狀態值 | 說明 | |
|---|---|---|
Unstarted | 尚未呼叫 Start() | |
Running | 正常執行中 | |
WaitSleepJoin | 阻塞於 Wait、Sleep、Join | |
Suspended | 已呼叫 Suspend() (已淘汰) | |
SuspendRequested | 要求暫停但尚未生效 (已淘汰) | |
AbortRequested | 已呼叫 Abort() 但尚未終止 | |
Stopped / Aborted | 已結束 (正常或被中止) | |
Background | 標記為背景執行緒 (非獨立狀態,配合 IsBackground 屬性) |
| 特性 | 前景執行緒 (IsBackground=false) | 背景執行緒 (IsBackground=true) |
|---|---|---|
| 預設值 | 手動建立的 Thread 預設為前景 | ThreadPool、Task 預設為背景 |
| 程式結束條件 | **所有前景執行緒結束** → 程式結束 (CLR 強制終止所有背景執行緒) | 不阻止程式結束 |
| 適用場景 | 關鍵業務邏輯、必須完成的工作 | 輔助工作、監聽、快取清理、非關鍵批次 |
| 需求 | 推薦方案 | 理由 |
|---|---|---|
| 現代非同步程式設計、回傳值、續作、取消、異常處理 | Task.Run / async/await | 語法簡潔、組合性強、預設用 ThreadPool、支援 CancellationToken |
| 火燒忘背景工作、無回傳值、舊版相容 | ThreadPool.QueueUserWorkItem | 輕量、無 Task 物件開銷 |
| 需精細控制:名稱、優先級、IsBackground、單一實例、長時間運行 | new Thread(...) | 完整控制執行緒屬性與生命週期 |
| STA 單元執行緒 (COM、UI、Clipboard) | new Thread(() => { ... }) { ApartmentState = ApartmentState.STA }.Start() | Task 預設 MTA,無法直接設定 STA |
| 需自訂排程器、長時間 CPU 密集工作不佔用 ThreadPool | Task.Factory.StartNew(..., TaskCreationOptions.LongRunning) | 建立專用執行緒,不影響 ThreadPool 可用度 |
Thread 類別提供了對作業系統執行緒最直接的控制能力:建立、啟動、命名、優先級、前景/背景模式、Join 等待、Sleep 讓步、Interrupt 中斷阻塞、ThreadState 狀態觀察。雖然現代 .NET 開發**強烈建議優先使用 Task / async/await**,但深入理解 Thread 機制對於:除錯死結/競爭條件、維護舊版程式碼、實作 STA 需求、自訂排程器、理解 ThreadPool/Task 底層運作,具有不可替代的價值。核心原則:**避免使用 Abort/Suspend/Resume、善用 CancellationToken 取消、最小化共享狀態、優先使用高階抽象**。