老趙在前幾次的post裡分析了.net的自帶執行緒池,由於.net自帶的執行緒池在底層通過win32api呼叫的windows的程序附帶的執行緒池,所以對於程序,這個執行緒池是唯一的,而且很不幸的是很多.net自身的操作也需要通過這個執行緒池來完成,比如timmer。所以我們來嘗試自己寫乙個執行緒池,這個執行緒池不是靜態的,乙個程序裡可以出現多個執行緒池的例項,我們可以隨時放入要執行的操作,由於沒有系統執行緒池的建立執行緒的頻率的限制,對於大量突發執行緒的頻繁操作來說自定義的執行緒池會比較好用。
首先我們來分析一下實現的原理。執行緒池,顧名思義就是在乙個「池」中儲存了一組可以重複利用的執行緒物件,從而可以節省建立執行緒的開銷。那麼首要需要解決的問題就是復用執行緒了。在.net中我們建立乙個執行緒的方式可以是:
thread t我們可以把執行緒看作是方法的乙個包裝,那麼我們要復用執行緒就需要能夠動態的改變執行緒體的方法。為了達到這個目的,我們需要把具體要執行的方法包裝一下,這裡我們就通過delegate來包裝,然後用另外乙個方法來代替被包裝的方法稱為執行緒體。如下:=new
thread(method);
static object context;
static waitcallback tbodyinstance = new waitcallback(tbody);
}static void tbody(object arg)
如此這般,當執行緒被掛起的時候,我們就能夠修改tbodyinstance,那麼就等於修改了執行緒體要執行的**,而執行緒被掛起之後就相當於是閒置起來了。
class task : idisposable
public event actionworkcomplete; //當執行完成後通知執行緒池執行後續操作的事件
public task()
public void active()
public void setworkitem(waitcallback action, object context)
private void work()
}public void close()
public void dispose()
catch }}
如此這般,當執行緒包裝器初始化的時候,執行緒就啟動並被阻塞掛起,這個時候我們可以設定執行緒執行的方法體委派,並且指定傳遞給執行緒的引數.當執行active方法後執行緒被喚醒,並開始執行執行緒體,當執行緒體執行完之後會開始新迴圈並被繼續掛起,如此這般周而復始。由此我們完成了對執行緒物件的服用。
----------------------我是分割線------------------------
接下來我們需要乙個容器來儲存和管理這些可復用的執行緒包裝器,這個容器也就是所謂的執行緒池了。為了方便描述,以下我們簡稱執行緒包裝器類為執行緒。
我們首先需要乙個物件來儲存所有已經建立出來的執行緒。為了同時方便定位特定的執行緒,我們給每個執行緒增加乙個id的屬性,在建立的時候用guid來賦值,這樣我們就能用dictionary來儲存所有已經建立出來的執行緒引用。
為了減少遍歷,我們將正在工作的執行緒也放在乙個dictionary中,最後把所有空閒的執行緒放在乙個queue裡頭。
由於不能無限量的增加執行緒,所以設定了最大執行緒數的限制,所以如果當需要執行的執行緒超過的時候為了不丟擲異常,我們需要用乙個結構來吧要執行的操作和資料加入佇列,在有空閒執行緒的時候好取出來繼續執行。
所以我們需要重點實現的就是兩個過程,乙個是加入執行緒,乙個是當執行緒執行完畢後所執行的操作。
最後我們來看看完整實現的**:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading;
namespace taskpooltest
}//設定最小執行緒數
public void setminthread(int value)
}//設定增量
public void setincrement(int value)
}//初始化執行緒池
public taskpool()
}//執行緒執行完畢後的觸發事件
void t_workcomplete(task obj)
else
//設定執行緒的執行委託物件和上下文物件
nt.taskworkitem = item.works;
nt.contextdata = item.context;
//新增到工作字典中
working.add(nt.key, nt);
//喚醒執行緒開始執行
nt.active();
}else
else}}
}//新增工作委託的方法
public void addtaskitem(waitcallback taskitem, object context)
else
else
}//從空閒佇列提出出來設定後開始執行
t = freequeue.dequeue();
working.add(t.key, t);
t.taskworkitem = taskitem;
t.contextdata = context;
t.active();
return;}}
else);}
}}//**資源
public void dispose()
}publicpool.clear();
working.clear();
waitlist.clear();
freequeue.clear();
}//儲存等待佇列的類
class waititem
public object context }}
//執行緒包裝器類
class task : idisposable
public event actionworkcomplete; //執行緒完成一次操作的事件
//用於字典的key
public string key
//初始化包裝器
public task()
//喚醒執行緒
public void active()
//設定執行委託和狀態物件
public void setworkitem(waitcallback action, object context)
//執行緒體包裝方法
private void work()
}//關閉執行緒
public void close()
//**資源
public void dispose()
catch }}
}
最後看看如何使用這個執行緒池類:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading;
namespace taskpooltest
}, i);
}console.readkey();}}
}
執行的結果
自定義執行緒池
有些時候 jdk自帶的cachedthreadpool fixedthreadpool等執行緒池完成不了我們業務的需求時 可以用threadpoolexecutorg構造自定義的執行緒池。public class usethreadpoolexecutor1 這段 會首先執行任務1,然後把2 3 4...
自定義執行緒池
建立執行緒池方法 儘管executors提供了四種執行緒池建立的方式,但為了實現某些特定的需求,可以自己建立執行緒池。如在阿里的程式設計規範使用executors建立執行緒時,一般會報錯,並提示以下資訊 執行緒池不允許使用executors去建立,而是通過threadpoolexecutor的方式,...
自定義執行緒池
自定義執行緒池建立api 執行緒池建立通過juc的介面 executor 實現,平時我們使用其實現類 threadpoolexecutor 實現自定義執行緒池。常用建構函式 public threadpoolexecutor int corepoolsize,int maximumpoolsize,...