4

私は各タイムステップで、多くのモデルをシミュレートする必要があるシミュレーションシステムで作業します。Java再利用エグゼキュータ

ExecutorService executor = Executors.newFixedThreadPool(nThread); 
for (Model m : models) { 
    executor.execute(m.simulationTask()); 
} 
executor.shutdown(); 
while (! executor.awaitTermination(10, TimeUnit.MINUTES)) { 
    System.out.println("wait"); 
} 

さて、executorがshutdown()を呼び出した後​​新しいタスクに使用することはできません:私は計算をスピードアップするためにFixedThreadPoolを使用しました。エグゼキュータをリセットする方法があるので、次のシミュレーションステップで既存のエグゼキュータ(およびそのスレッド)を再利用できますか?

答えて

7

あなたはエグゼキュータのサービスを再利用することができます。

Collection<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(16); 
for (Model m : models) { 
    tasks.add(m.simulationTask()); 
} 

ExecutorService executor = Executors.newFixedThreadPool(nThread); 
try { 
    executor.invokeAll(tasks); 
} catch(InterruptedException ie) { 
    // Handle this 
} 

基本的に、すべてのタスクを収集して実行し、実行する前に実行を待機します。もちろん、あなたのタイムステップごとに新しいExecutor Serviceを使用することもできますが、少なくともオプションはあります。

警告:エラーが発生する可能性があるため、コードをコンパイルしませんでした。私はまた、便宜上、Integerパラメータ型を前提としていました。

+1

次のステップに進む前に、すべてのタスクの完了を待つ方法を示していません。 – dogbane

+1

@dogbane - 'invokeAll'は、すべてのタスクが完了するのを待ちます。 – Perception

+0

彼は値を返さない 'execute(Runnable)'を使っているので、おそらく 'Callable 'に行くことができますか? – mzzzzb

1

Executorインターフェイスの独自の実装を記述することができます。それ以外にも、私が気づいているデフォルトの実装のほとんどは、shutdown()の後にスレッドを刈り取り、メモリをクリーンアップするので、私の知る限り、あらかじめ作成された解決策はありません。新しいExecutorをaccquiringよりも良いだろう再起動、おそらくあなたはチュートリアルに見えるabout extending ThreadPoolExecutor with a pause/resume set of methodsの代わりに、未する機能を追加しなければならない理由

shutdown()はクリーンアップとガベージコレクションの多くを行う可能性があることを考えると、それは必ずしも明らかではありませんシャットダウン。

0

もう一度ExecutorServiceを取得してください。とにかくオーバーヘッドは最小です。

同じエグゼキュータを再利用することを主張する場合は、独自のバリアーメカニズムを実装できます。新しいタスクを提出すると、カウンターを原子的に増やします。タスクが終了すると、カウンターが原子的に減少します。メインスレッドでは、カウンタがゼロになるまで待ちます。ような何か:

// globally visible objects 
AtomicInteger counter = new AtomicInteger(0); 
Object signal = new Object(); 

ExecutorService executor = Executors.newFixedThreadPool(nThread); 
for (Model m : models) { 
    counter.getAndIncrement(); 
    executor.execute(m.simulationTask()); 
} 

synchronized(signal) { 
    while(count.get() > 0) { 
     signal.wait(); 
    } 
} 

は、その後、あなたの仕事のrun内側:あなたがややあなたのコードを再構築した場合

public void run() { 
    // original code 
    // at the end: 
    synchronized(signal) { 
     counter.getAndDecrement(); 
     signal.notify(); 
    }   
} 
+0

私はThreadPoolに裏打ちされたExecutorの作成に最小限のオーバーヘッドがあるとは言いません... –

+0

彼が使用しているスレッドの数によって異なります。数字が小さい場合、オーバーヘッドはあまりありません。また、彼が実行しているタスクが粗粒であれば、残りのアプリケーションに関しては無視できます。 – Tudor

1

あなたのクラスのメンバーとしてExecutorServiceを宣言し、必要に応じて再利用してください。それ以上のタスクを受け入れないので、shutDown()を呼び出さないでください。もちろん、あなたの仕事はきれいに終わるべきですし、ある時点で終わらなければなりません。