| 著作一覧 |
スレッドを使い捨てでばんばん作るサーブレットコンテナを使うんだったら、ThreadLocalはあまり意味がない(だって、ThreadLocalに保存しても2度目はないわけだから)。というかオーバーヘッドだけがある。
でもサーブレットコンテナがスレッドプールを使うかどうかは実装に依存している。
ってことは、ThreadLocalを使うかスタック(たとえばdoPostとかの中で)に作るかを決定するのに、サーブレットコンテナの実装詳細を知る必要が出てくるわけだが。
別の戦略もある。
ThreadLocalのかわりに自分でプールを作る方法だ。LinkedListが本来だけど結構重いから開き直ってArrayListでもかまわないけど。
List freeResources = new LinkedList();
public void init(ServletConfig cfg) throws ServletException {
super.init(cfg);
for (int i = 0; i < Integer.intValue(cfg.getInitParameter("nrOfResources"); i++) {
// あらかじめプールする場合
freeResources.add(new FooBarResource(cfg));
}
}
....
public void dpPost(...) {
FooBarResource fb = null;
synchronized(freeResources) {
if (freeResources.size() > 0) {
fb = (FooBarResource)freeResources.remove(0);
} // 後からプールを作成する場合にはここで作っても良い。
}
if (fb == null) {
resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVALIABLE);
return;
}
try {
....
} finally {
synchronized(freeResources) {
freeResources.add(fb);
}
}
}
public void destroy() {
for (Iterator i = freeResources.iterator(); i.hasNext();) {
((FooBarResource)i.next()).cleanup(); // クリーンアップが必要な場合
}
freeResources.clear();
}
ThreadLocalよりちょっと有利なのは、後処理が素直に可能な点。後処理が必要なリソースの場合、ThreadLocalを使っても結局、destroyでクリーンアップするためにどこかに全部がめておかなければならなくなる。
ジェズイットを見習え |