2017-09-28 8 views
1

を使用したとき、私はクラスCollectorと、このようなThreadLocalScopeています旧世代メモリが増加ThreadLocalの

Collector { 
    Collector() { 
     events = new LinkedList<>(); 
    } 

    add(Event e) { 
     events.add(e); 
    } 

    flush() { 
     LinkedList<Event> copy = events; 
     new Thread(() -> { 
      for (Event e : copy) { 
       sendToServer(e); 
      } 
      copy.clear(); 
     ).start(); 

     events = new LinkedList<>(); 
    } 
} 

ThreadLocalScope { 
    public static ThreadLocal<Collector> local = new ThreadLocal<>() { 
     protected Collector initialValue() { 
      return new Collector(); 
     } 
    } 
} 

Collectorは、単純にイベントを追加し、flushが呼び出されたときに新しいスレッドでAPIにこれらのイベントを送信します。 CollectorThreadLocalで初期化されます。

また、(Quartzを使用して)何度も実行されるJobクラスもあります。このすべてが素晴らしい作品のように定義された場合:

Job { 
    execute() { 
     for (int i = 0; i < 100,000; i++) { 
      ThreadLocalScope.get().add(new Event()); 
     } 
     ThreadLocalScope.get().flush(); 
    } 
} 

代わりに、私はこのように集電体上に保持する場合は:

Job { 
    Collector collector; 
    Job() { 
     collector = ThreadLocalScope.get(); 
    } 

    execute() { 
     for (int i = 0; i < 100,000; i++) { 
      collector.add(new Event()); 
     } 
     collector.flush(); 
    } 
} 

私は旧世代のメモリ使用量が急激に増加し、ストップ世界をガベージコレクションサイクルご覧くださいいつも起こっている。唯一の違いは、毎回ThreadLocalScope.get()を呼び出すのではなく、Collectorをメンバー変数として追加したことです。

この増加は、イベントが旧世代に移動されていることを意味します。しかし、なぜそれが起こるだろうか? Collectorはすぐにイベントへの参照をすべてクリアします。したがって、GCedでない場合でもイベントは発生しています。

答えて

0

私は言った:

を私はあなたがここにスレッドの安全性の問題を持っているかもしれないと思います。

間違っています。私はそれがそれより簡単だと思う。

最初のバージョンでは、ジョブを実行しているスレッドのコンテキストでThreadLocalScope.get()を呼び出しています。

2番目のバージョンでは、Job()オブジェクトを作成しているスレッドのcontrextでThreadLocalScope.get()を呼び出しています。それは変数内で検索され、後でexecutorスレッドで使用されます。 Job()オブジェクトがすべて同じスレッド上に作成されているとすると、そのメソッドは同じコレクタオブジェクトを共有していることを意味します(​​)。そして、彼らは潜在的に別のスレッドで実行されています。 Collectorはスレッドセーフではないため、危険です。

あなたが気づいていないこともあります。 Quartzがスレッドプールを使用している可能性があります。つまり、​​コールが終了すると、スレッドはプールに戻ります。次回は、Quartzが同じスレッドを使用する場合、前回のオブジェクトCollectorを再利用します。

+0

ThreadLocalは、その変数にアクセスできるスレッドが1つだけであることを意味します。したがって、各スレッドには独自の 'Collector'インスタンスがあります。正しい競合条件はありませんか? – dg428

+0

はいクォーツはスレッドを再利用します。しかし、私はjob creationとexecute()が同じスレッド上で動作することを確認しました。私はイベントをクリアするので、次の仕事のためのコレクターの募集は問題ではない – dg428

+0

まだ、私はあなたの問題の根源だと思う。そして、正直言って、スレッドローカルは効率を助けていないし、そのようなスレッドを作成する 'flush()'は大きなパフォーマンスヒットです。 –

関連する問題