私の ThreadLocal の使用
私の Java クラスでは、ThreadLocal
主に不必要なオブジェクトの作成を避ける手段として aを使用することがあります。
@net.jcip.annotations.ThreadSafe
public class DateSensitiveThing {
private final Date then;
public DateSensitiveThing(Date then) {
this.then = then;
}
private static final ThreadLocal<Calendar> threadCal = new ThreadLocal<Calendar>() {
@Override
protected Calendar initialValue() {
return new GregorianCalendar();
}
};
public Date doCalc(int n) {
Calendar c = threadCal.get();
c.setTime(this.then):
// use n to mutate c
return c.getTime();
}
}
私がこれを行うのは適切な理由からです -GregorianCalendar
値を表すのではなく、複数の呼び出しにわたってサービスを提供する、輝かしくステートフルで、変更可能な、非スレッドセーフなオブジェクトの 1 つです。さらに、インスタンス化するのは「費用がかかる」と見なされます(これが正しいかどうかは、この質問のポイントではありません)。(全体として、私は本当にそれを賞賛します:-))
Tomcat の鳴き声
ただし、スレッドをプールし、アプリケーションがそれらのスレッドのライフサイクルを制御できない環境でこのようなクラスを使用すると、メモリ リークが発生する可能性があります。サーブレット環境が良い例です。
実際、Web アプリケーションが停止すると、Tomcat 7 は次のように動作します。
重大: Web アプリケーション [] は、タイプ [org.apache.xmlbeans.impl.store.CharUtil$1] (値 [org.apache.xmlbeans.impl.store.CharUtil$1@2aace7a7]) のキーと値を持つ ThreadLocal を作成しましたタイプ [java.lang.ref.SoftReference] (値 [java.lang.ref.SoftReference@3d9c9ad4]) ですが、Web アプリケーションが停止したときに削除できませんでした。スレッドは、メモリ リークの可能性を回避するために、時間の経過とともに更新されます。2012 年 12 月 13 日午後 12:54:30 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
(その特定のケースでは、私のコードでさえそれを行っていません)。
誰が悪いのか?
これは公正とは思えません。Tomcat は私(または私のクラスのユーザー) が正しいことをしたと非難しています。
最終的には、Tomcat が私に提供したスレッドを他のWeb アプリで再利用したいからです。(うーん、私は汚れているように感じます。) おそらく、それは Tomcat 側の優れたポリシーではありません - スレッドには実際に状態がある/原因があるためです - アプリケーション間でそれらを共有しないでください。
ただし、このポリシーは、望ましくない場合でも、少なくとも一般的です。ThreadLocal
ユーザーとして、クラスがさまざまなスレッドにアタッチしたリソースをクラスが「解放」する方法を提供する義務があると感じています。
しかし、それについて何をすべきか?
ここで何をするのが正しいですか?
私には、サーブレット エンジンのスレッド再利用ポリシーが の背後にある意図と矛盾しているように思えますThreadLocal
。
しかし、ユーザーが「スレッドを死なせて GC に任せる立場にないにもかかわらず、このクラスに関連付けられたスレッド固有の状態をなくす」と言うことができるようにする機能を提供する必要があるかもしれません。私がこれを行うことは可能ですか?つまり、過去のある時点でThreadLocal#remove()
見た各スレッドで呼び出されるように手配できるわけではありません。ThreadLocal#initialValue()
それとも別の方法がありますか?
それとも、ユーザーに「適切なクラスローダーとスレッドプールの実装を取得してください」と言うべきですか?
EDIT#1 :threadCal
スレッドのライフサイクルを認識しない vanailla ユーティリティ クラスでの使用方法を
明確化EDIT#2 : スレッド セーフの問題を修正DateSensitiveThing