2015-12-01 7 views
6

実行スレッドを1つ使用するようにForkJoinPoolを設定することはできますか?シングルスレッドのForkJoinPoolを設定するには?

私はForkJoinPoolの中にRandomを呼び出すコードを実行しています。それが実行されるたびに、私は異なるランタイム動作になり、回帰を調べることが難しくなります。

"debug"と "release"モードを提供するコードベースが欲しいです。 「デバッグ」モードでは、固定シードでRandomを構成し、単一の実行スレッドでForkJoinPoolを構成します。 「リリース」モードでは、システム提供のRandomシードが使用され、デフォルト数のForkJoinPoolスレッドが使用されます。

ForkJoinPoolの並列処理を1に設定しようとしましたが、2つのスレッド(mainと2番目のワーカースレッド)が使用されています。何か案は?

+0

リリースモードhttps://docs.oracle.com/javase/tutorial/essential/concurrency/threadlocalrandomのためにランダム実行はるかに良いがあります。html – zapl

+0

@zapl私はすでにリリースモードで 'ThreadLocalRandom'を使用しています。この質問はパフォーマンスの向上に関するものではありません。これは、 'ForkJoinPool'が単一のスレッドを使用するように設定することで、デバッグの容易性を改善することです。 – Gili

+0

並列処理を0に設定しようとしましたか? – pvg

答えて

7

私は間違っていたことが判明しました。

ForkJoinPoolparallelismに設定すると、1つのスレッドだけがタスクを実行します。 mainスレッドはForkJoin.get()でブロックされています。実際にはどのタスクも実行されません。

つまり、決定論的な振る舞いを提供するのは本当に難しいことです。ここで私は修正しなければならなかった問題のいくつかされています。ワーカースレッドが十分に長いアイドル状態になった場合

  • ForkJoinPoolは、(異なる名前で)異なるワーカースレッドを使用してタスクを実行していました。たとえば、メインスレッドがデバッグブレークポイントで一時停止した場合、ワーカースレッドはアイドル状態になりシャットダウンします。実行を再開すると、ForkJoinThreadは別の名前の新しいワーカースレッドをスピンアップします。これを解決するには、私はprovide a custom ForkJoinWorkerThreadFactory implementation that returns null if the ForkJoinPool already has a live workerでなければなりませんでした(これによりプールには複数のワーカーが作成されません)。私はまた、ワーカースレッドがシャットダウンして再び戻ってきた場合でも、自分のコードが同じRandomインスタンスを返すようにしていました。非決定論的な繰り返し順序を持つ
  • コレクションは、このようなHashMapHashSetとして実行ごとに異なる順序で乱数をつかむ要素につながりました。私はLinkedHashMapLinkedHashSetを使ってこれを修正しました。
  • Enum.hashCode()などの非確定的なhashCode()実装を持つオブジェクト。私はこの問題の原因を忘れてしまいましたが、組み込みのメソッドに頼るのではなく、hashCode()を自分で計算して修正しました。ここで

ForkJoinWorkerThreadFactoryのサンプル実装です:

class MyForkJoinWorkerThread extends ForkJoinWorkerThread 
{ 
    MyForkJoinWorkerThread(ForkJoinPool pool) 
    { 
     super(pool); 
     // Change thread name after ForkJoinPool.registerWorker() does the same 
     setName("DETERMINISTIC_WORKER"); 
    } 
} 

ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory() 
{ 
    private WeakReference<Thread> currentWorker = new WeakReference<>(null); 

    @Override 
    public synchronized ForkJoinWorkerThread newThread(ForkJoinPool pool) 
    { 
     // If the pool already has a live thread, wait for it to shut down. 
     Thread thread = currentWorker.get(); 
     if (thread != null && thread.isAlive()) 
     { 
      try 
      { 
       thread.join(); 
      } 
      catch (InterruptedException e) 
      { 
       log.error("", e); 
      } 
     } 
     ForkJoinWorkerThread result = new MyForkJoinWorkerThread(pool); 
     currentWorker = new WeakReference<>(result); 
     return result; 
    } 
}; 
+0

良いThreadFactoryに関連するいくつかの重要なコードブロックを投稿すると、他の人には役に立ちます。 –

+0

優れています。特にワーカースレッド拡張。 –

0

メインスレッドは、常にアプリケーションが作成する最初のスレッドです。したがって、ForkJoinPoolparallelism,1で作成すると、別のスレッドが作成されます。効果的にはアプリケーションの中に2つのスレッドが存在します(スレッドのpoolを作成したためです)。

メインのスレッドが1つだけ必要な場合は、コードを順番に実行することができます(並行して実行することはできません)。

+0

私はすでにこれを知っています。明確にするために、残りのコードを変更せずに 'ForkJoinPool'が使用するスレッドの数を変更する必要があります。 'ForkJoinPool'の使用をダンプして順番にコードを実行すると、「デバッグ」モードと「リリース」モードを切り替えるたびにデザインレベルの変更が行われます。 – Gili

+0

問題を示す小さなコードで質問を更新できますか? – tuxdna

関連する問題