9

ThreadLocal実際に初期化せずに a が初期化されているかどうかをテストしたい。もちろん、コードはスレッドセーフである必要があります。理想的には、次のようなものが必要です。

class TestableThreadLocal<T> extends ThreadLocal<T> {
    public boolean isInitialized() {
        ...
    }
}

しかし、このメソッドをどのように実装しますか?

編集: 動機: aThreadLocalをオーバーライドしてサブクラス化しましたinitialValue()。ただし、特にマルチクラスローダー環境でメモリ リークが発生する可能性があるため、常に初期化が必要なわけではありません。偶発的な初期化を回避するコードを作成するには、簡単なテストが役立ちます。

4

4 に答える 4

11

私はクラスローダのリークを避けるために単純なルールを使用する傾向があります。確かにそれらは面倒ですが、いくつかのラッピングを使用すればそれほど悪くはありません。はい、リークは悪です。

  • 決してオーバーライドしないinitialValueでください-あなたはただトラブルを求めているだけで、それが存在することを忘れてください.
  • そうしない限り、ThreadLocal に非システム/非ブートストラップ クラスを格納しないでください。threadLocal.set(xxx); try{...process...}finally{threadLocal.set(null);}
  • それでも initialValue をオーバーライドする場合は、threadLocal.remove()notを使用してくださいthreadLocal.set(null)
  • または、ハード参照を保持するプールからの値にWeakReferene(つまり ThreadLocal ) を使用します。<WeakReference<Foo>>直感に反するように見えるかもしれませんが、プールがクリアされると値が消え、クラスは自由に GC できるようになります

投稿があなたの質問への直接の回答ではないことは承知していますが、あなたが望むものを達成し、リークを寄せ付けないようにする簡単な方法はありません.

于 2012-08-06T10:43:19.120 に答える
2

考え:

  • ThreadLocal.get呼び出されると、値が初期化されます。
  • 初期化したくない場合は、値を保存する必要はありません(まったく、これまでに)
  • 初期化を避けたい場合はget、 ではなくをオーバーライドすることから始めましょうinitialValue
  • ThreadLocal別の道を歩む -封じ込めとは対照的に、本当に継承する必要がありますか?
于 2012-08-12T01:35:03.390 に答える
1

私はあなたの最初の質問に混乱しています。あなたが作成している ThreadLocal ですか、それとも他の誰かの API によって既に提供されていますか?

ThreadLocal を作成している場合は、初期値を提供できるように initialValue() をオーバーライドする必要があることを既に知っていると思います。

その場合、それが呼び出されて値が作成されたかどうかをいつでも追跡できます。

以下のこのコードのようなものがあなたが望むことをすると思います:

MyThreadLocal<T> extends ThreadLocal<T>{

   Map<Thread,Boolean> myThreadMap = new HashMap<Thread,Boolean>();

   protected T initialValue(){
         synchronized(myThreadMap){
               T value =  ... your code to create initial value
               myThreadMap.put(Thread.currentThread(),true);
               return T;
         }
   }

   public boolean containsThreadValues(){
          synchronized(myThreadMap){
                 return myThreadMap.isEmpty();
          }
   }

   public boolean isInitializedForThisThread(){
         synchronized(myThreadMap){
                 return myThreadMap.get(Thread.currentThread())==true;
         }
   }


}

myThreadMap には、デッド スレッドであっても、常に古いキーが含まれます。古いキーを消去したい場合は、それを WeakHashMap に置き換えます。次に、ThreadLocal を使用していた Threads がなくなると、キーが削除されます。

于 2012-08-13T07:33:49.350 に答える
1

ThreadLocal には、値が初期化されているかどうかを知らせる API がないため、これを行う数少ない方法の 1 つにリフレクションが含まれます。

リフレクションを使用して「コーディング」することは確かに可能です。ただし、すべての通常の警告が適用されます。リフレクション コードは、java.lang.ThreadLocal とその非パブリック メンバーの実装の詳細に大きく依存します。JDK ベンダーが実装を変更した瞬間に、コードが壊れます。

于 2012-07-14T17:59:32.437 に答える