8

私はマルチスレッドアプリケーションでJavaエグゼキューを使用しましたが、私は、次の方法のそれぞれに使用するのが最善であるとき見つけ出すように見えることはできません。Java Executorを正しく使用するには?

1.

ExecutorService executor=Executors.newFixedThreadPool(50); 
executor.execute(new A_Runner(... some parameter ...)); 
executor.shutdown(); 
while (!executor.isTerminated()) { Thread.sleep(100); } 

2は、 [2]私は何をスキップした場合における具体。

int Page_Count=200; 
ExecutorService executor=Executors.newFixedThreadPool(50); 
doneSignal=new CountDownLatch(Page_Count); 
for (int i=0;i<Page_Count;i++) executor.execute(new A_Runner(doneSignal, ... some parameter ...)); 
doneSignal.await(); 
executor.shutdown(); 
while (!executor.isTerminated()) { Thread.sleep(100); } 
int Executor_Count=30; 
ThreadPoolExecutor executor=new ThreadPoolExecutor(Executor_Count,Executor_Count*2,1,TimeUnit.SECONDS,new LinkedBlockingQueue()); 
List<Future<String>> futures=new ArrayList<>(3330); 

for (int i=0;i<50;i++) futures.add(executor.submit(new A_Runner(... some parameter ...)); 
executor.shutdown(); 
while (!executor.isTerminated()) { executor.awaitTermination(1,TimeUnit.SECONDS); } 
for (Future<String> future : futures) 
{ 
    String f=future.get(); 
    // ... 
} 

、 doneSignalの場合、それは[1]のようになりますので、doneSignalの使用は何ですか?

また、[3]では、doneSignalを追加するとどうなりますか?それとも可能ですか?

私が知りたいのは、これらのアプローチは互換性があるのですか、または上記の特定のタイプを使用するはずの特定の状況がありますか?

答えて

10
  1. ExecutorService

    ExecutorService executor=Executors.newFixedThreadPool(50);

    これは、シンプルで使いやすいです。それはThreadPoolExecutorの低レベルの詳細を隠す。

    Callable/Runnableタスクの数が少なく、無制限キューのタスクを積み重ねてもメモリが増加しない場合は、この値を推奨します。&は、システムのパフォーマンスを低下させます。 CPU/Memoryの制約がある場合は、容量制限& RejectedExecutionHandlerThreadPoolExecutorを使用して、タスクの拒否を処理します。

  2. CountDownLatch

    あなたは与えられた数でCountDownLatchを初期化してきました。このカウントは、countDown()メソッドへの呼び出しによって減分されます。私はあなたがあなたのRunnableタスクで後に減量を呼んでいると仮定しています。このカウントがゼロになるのを待っているスレッドは、await()メソッドの1つを呼び出すことができます。 await()を呼び出すと、カウントがゼロになるまでスレッドがブロックされます。 このクラスは、他のスレッドセットがタスクを完了するまでJavaスレッドを待機させます。

    ユースケース:

    1. 最大並列の実現:時々、私たちは

    2. 最大並列処理を実現すると同時に、スレッドの数を開始したい開始前に完了するためにN個のスレッドを待って実行

    3. デッドロック検出。

      詳しくはLokesh Guptaのarticleをご覧ください。

  3. ThreadPoolExecutor:それは、さまざまなスレッドプールのパラメータを微調整するために、より制御を提供します。アプリケーションが有効な数のアクティブなRunnable/Callableタスクによって制約されている場合は、最大容量を設定して境界キューを使用する必要があります。キューが最大容量に達すると、RejectionHandlerを定義できます。 Javaでは、4種類のRejectedExecutionHandlerpoliciesが提供されています。デフォルトThreadPoolExecutor.AbortPolicy

    1. 、ハンドラが拒否すると、実行時のRejectedExecutionExceptionをスローします。

    2. ThreadPoolExecutor.CallerRunsPolicyでは、executeを呼び出すスレッドがタスクを実行します。これは、新しいタスクが提出される速度を遅くする単純なフィードバック制御メカニズムを提供する。

    3. ThreadPoolExecutor.DiscardPolicyでは、実行できないタスクは単純に削除されます。 (これが繰り返されることを引き起こす、再び失敗することができる。)executorがシャットダウンされていない場合ThreadPoolExecutor.DiscardOldestPolicy

    4. は、作業待ち行列の先頭のタスクは廃棄され、そして実行は再試行される

      CountDownLatchの動作をシミュレートする場合は、invokeAll()メソッドを使用できます。あなたが引用しませんでした

  4. もう一つのメカニズムは、ForkJoinPool

    ForkJoinPoolForkJoinPoolは、Java ExecutorService のが、1つの相違点と類似しているのJava 7でJavaに追加されました。 ForkJoinPoolは、 タスクを簡単に小さなタスクに分割し、 をForkJoinPoolに送信します。空きワーカースレッドがビジー状態のワーカースレッドキューからタスクを奪うと、タスクスチールがForkJoinPoolで発生します。

    Java 8はwork stealing poolを作成するためにExecutorServiceにもう1つのAPIを導入しました。 RecursiveTaskRecursiveActionを作成する必要はありませんが、それでもForkJoinPoolを使用できます。

    public static ExecutorService newWorkStealingPool() 
    

    その標的並列レベルとして利用可能なすべてのプロセッサを使用してワークスチールスレッドプールを作成します。

    デフォルトでは、パラメータとしてCPUコアの数が使用されます。

これらの4つのメカニズムはすべて相互に補完的です。制御したい細かさのレベルに応じて、適切なものを選択する必要があります。

関連する問題