19

ThreadLocalについての私の限られた理解は、リソース リークの問題があるということです。この問題は、ThreadLocalでWeakReferencesを適切に使用することで解決できると思います (ただし、この点を誤解している可能性があります)。WeakReference で ThreadLocal を正しく使用するためのパターンまたは例があれば、それが必要です。たとえば、このコード スニペットでは、WeakReference はどこに導入されますか?

static class DateTimeFormatter {
    private static final ThreadLocal<SimpleDateFormat> DATE_PARSER_THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() {
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy/MM/dd HH:mmz");
        }
    };
    public String format(final Date date) {
        return DATE_PARSER_THREAD_LOCAL.get().format(date);
    }
    public Date parse(final String date) throws ParseException
    {
      return DATE_PARSER_THREAD_LOCAL.get().parse(date);
    }
}
4

8 に答える 8

36

ThreadLocalWeakReference内部で使用します。が強く参照されていない場合、ThreadLocalさまざまなスレッドがそれを介して格納された値を持っていても、ガベージ コレクションされますThreadLocal

さらに、ThreadLocal値は実際にはThread;に格納されます。スレッドが終了すると、そのスレッドに関連付けられたすべての値ThreadLocalが収集されます。

最終的なクラス メンバーとしてがある場合ThreadLocal、それは強い参照であり、クラスがアンロードされるまで収集できません。ただし、これはどのクラス メンバーも動作する方法であり、メモリ リークとは見なされません。


更新:引用された問題は、循環参照のようなThreadLocalものを強く参照している場合にのみ発生します。ThreadLocal

この場合、値 (a SimpleDateFormat) には への後方参照はありませんThreadLocal。このコードにはメモリ リークはありません。

于 2009-06-02T16:57:33.443 に答える
11

SimpleDateFormat はスレッドセーフではないため、これらのフープを飛び越えていると思います。

上記の問題を解決していないことは承知していますが、日付/時刻の作業についてJodaを確認することをお勧めしますか? Joda には、スレッドセーフな日付/時刻の書式設定メカニズムがあります。Joda API は、新しい標準の日付/時刻 API 提案の基盤であるため、Joda API の学習に時間を無駄にすることはありません。

于 2009-06-02T16:45:51.147 に答える
4

そんな問題はないはずです。

スレッドの ThreadLocal 参照は、対応するスレッドが存続している間のみ存在するように定義されています (javadoc を参照)。別の言い方をすれば、スレッドが存続していない場合、ThreadLocal がそのオブジェクトへの唯一の参照であった場合、そのオブジェクトはガベージコレクションの対象になります。

つまり、本物のバグを見つけて報告する必要があるか、何か間違ったことをしているのです!

于 2009-06-02T16:35:21.490 に答える
3

これは厳密にはあなたの質問に対する答えではないことを理解していますが、原則としてThreadLocal、リクエスト/インタラクションの最後に明確な破棄がない状況を使用することはお勧めしません。クラシックはサーブレットコンテナでこの種のことを行っています。一見問題ないように見えますが、スレッドがプールThreadLocalされているため、各リクエストが処理された後でもリソースにハングアップする問題になります。

提案:

  1. 各インタラクションに同様のラッパーのフィルターを使用して、各インタラクションの最後にThreadLocalをクリアします
  2. 誰かがすでに提案しているように、commons-langやJodaのFastDateFormatなどのSimpleDateFormatの代替を使用できます。
  3. 必要になるたびに新しいSimpleDateFormatを作成するだけです。私が知っているのは無駄に思えますが、ほとんどのアプリケーションでは違いに気付かないでしょう
于 2009-06-02T17:35:57.200 に答える
1

@Neil Coffey の発言に付け加えると、 ThreadLocal インスタンスが静的である限り、これは問題になりません。静的インスタンスで get() を呼び出し続けるため、単純な日付フォーマッタへの同じ参照を常に保持する必要があります。したがって、ニールが言ったように、スレッドが終了すると、単純な日付フォーマッタの唯一のインスタンスがガベージ コレクションの対象となるはずです。

これがリソースの問題を引き起こすことを示す数値またはその他の形式のデバッグがある場合、それは別の話です。でもそのままで問題ないと思います。

于 2009-06-02T16:40:31.827 に答える
0

あなたの例では、 ThreadLocal を使用しても問題はありません。

スレッド ローカル (およびシングルトンも!) は、後でアンロードするクラスローダーによってロードされたインスタンスにスレッド ローカルが設定されている場合に問題になります。サーブレット コンテナー (Tomcat など) での典型的な状況:

  1. Web アプリケーションは、要求の処理中にスレッド ローカルを設定しました。
  2. スレッドはコンテナーによって管理されます。
  3. Web アプリケーションをアンデプロイする必要があります。
  4. スレッドローカルからインスタンス、そのクラス、そのクラスローダーへの参照が残っているため、webapp のクラスローダーはガベージできません。

シングルトン (webapp によって提供される java.sql.DriverManger および JDBC ドライバー) と同じです。

したがって、完全に制御できない環境では、特にそのようなことを避けてください。

于 2009-06-02T16:56:47.623 に答える
0

スレッド ローカルを使用後にクリーンアップするには、サーブレット フィルタを追加します。

protected ThreadLocal myThreadLocal = new ThreadLocal();

public void doFilter (ServletRequest req, ServletResponse res, chain) throws IOException, ServletException {
    試す {
        // ThreadLocal を設定します (例: リクエストごとに 1 回だけ実行される重い計算結果を保存するため)
        myThreadLocal.set(context());

        chain.doFilter(req, res);
    } 最後に {
        // 重要: メモリ リークを防ぐために ThreaLocal をクリーンアップします
        userIsSmartTL.remove();
    }
}
于 2013-12-23T12:53:50.547 に答える