在處理高併發任務時,.NET 內建的 ThreadPool 雖然方便,但靈活性有限:無法精確控制線程數量、空閒回收策略固定、任務隊列不可自定義。針對這些痛點,本文分享一個輕量級的自定義線程池 ThreadPoolEx,核心由三大組件構成:ThreadPoolEx(調度核心)、WorkItem(工作單元)、WorkQueue(線程安全隊列)。
MinThreadCount 到 MaxThreadCount 範圍。IdleTimeout 秒且線程數大於最小值時自動退出,避免資源浪費。Interlocked 原子操作維護 _inUseWorkThread,減少鎖競爭。public class ThreadPoolEx
{
private WorkQueue _workQueue = new WorkQueue();
public int MaxThreadCount = 10;
public int MinThreadCount = 2;
private Hashtable _threadTable = null;
private int _threadCount = 0;
private int _inUseWorkThread = 0;
public double IdleTimeout = 10;
public ThreadPoolEx() : this(10, 2, 2) { }
public ThreadPoolEx(int maxThreadCount, int minThreadCount, int idleTimeout)
{
MaxThreadCount = maxThreadCount;
MinThreadCount = minThreadCount;
IdleTimeout = idleTimeout;
_threadTable = Hashtable.Synchronized(new Hashtable(MaxThreadCount));
}
public void QueueUserWorkItem(WaitCallback waitCallback, object objParams)
{
EnqueueWorkItem(waitCallback, objParams);
}
private void EnqueueWorkItem(WaitCallback waitCallback, object objParams)
{
var workItem = new WorkItem
{
WorkCallback = waitCallback,
ObjParams = objParams
};
_workQueue.Push(workItem);
// 需要新線程時啟動
if (_inUseWorkThread + _waitWorkItem > _threadTable.Count)
{
StartThread();
}
}
// ... 省略部分代碼 ...
}
private void ProcessWorkItems()
{
try
{
while (true)
{
WorkItem workItem = _workQueue.Pop();
if (workItem == null)
{
bool isTimeout = CurThreadIsTimeOut();
if (isTimeout && _threadTable.Count > MinThreadCount)
break; // 退出線程
Thread.Sleep(100);
}
else
{
try
{
_threadTable[Thread.CurrentThread] = DateTime.Now;
Interlocked.Increment(ref _inUseWorkThread);
workItem.Execute();
}
catch (Exception)
{
// 記錄日誌
}
finally
{
Interlocked.Decrement(ref _inUseWorkThread);
}
}
}
}
catch (ThreadAbortException)
{
Thread.ResetAbort();
}
finally
{
if (_threadTable.Count > MinThreadCount)
_threadTable.Remove(Thread.CurrentThread);
}
}
class WorkQueue
{
private static object _lock = new object();
private Queue<WorkItem> _queue = new Queue<WorkItem>();
public WorkItem Pop()
{
lock (_lock)
{
return _queue.Count > 0 ? _queue.Dequeue() : null;
}
}
public void Push(WorkItem item)
{
lock (_lock)
{
_queue.Enqueue(item);
}
}
public int Count
{
get { lock (_lock) return _queue.Count; }
}
}
class WorkItem
{
public WaitCallback WorkCallback;
public object ObjParams;
public void Execute()
{
WorkCallback(ObjParams);
}
}
var pool = new ThreadPoolEx(maxThreadCount: 20, minThreadCount: 5, idleTimeout: 30);
for (int i = 0; i < 100; i++)
{
int taskId = i;
pool.QueueUserWorkItem(_ =>
{
Console.WriteLine($"Task {taskId} running on thread {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(100); // 模擬工作
}, null);
}
BlockingCollection 替代自旋等待,降低 CPU 佔用。PriorityQueue)。CancellationToken)支援。IThreadPool 介面,便於單元測試與替換。完整源碼可在文末下載。歡迎交流改進建議!