2017-10-22 9 views
2

ExecutorServiceスレッドのフロー規則に基づいて質問があります。 executonに複数のスレッドを追加したい場合は、スレッドが終了するまで待つことをお勧めします。実行中。ExecutorService:スレッドフロー規則の改善

これまでのところ、私はCountDownLatch()を使ってこれを行う方法を知っています。 1は、(.await後に追加のスレッドを追加することはできません、

public class Example{ 

public static void main(String[] args) throws InterruptedException { 

    CountDownLatch cdl = new CountDownLatch(2); //count of 2 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    executor.submit(new Runnable() { 
     public void run() { 
      method1(); //simulation of a useful method 1 
      cdl.countDown(); //reduces the count by one 
     } 
    }); 
    executor.submit(new Runnable() { 
     public void run() { 
      method2(); //simulation of a useful method 2 
      cdl.countDown(); 
     } 
    }); 
    cdl.await(); //will wait until both methods are complete 
    executor.submit(new Runnable() { 
     public void run() { 
     result(); //simulation of a method that needs previous threads to execute } 
     }); 
    } 
} 

非常に明白、このような方法は、このような作業のために最適ではない一つのことのために、次の例では3分の1が開始する前に完了する必要があり2つのスレッドを示しています)は、CDL自体に依存しません。

したがって、CDLと比較してスレッド実行をよりうまく操作できるように、ExecutorServiceでスレッドフローを調整する方が良いでしょうか。

+0

ありがとうございました!それでもCDLやFutureメソッドが優れているかどうかはまだ分かっていますが、少なくとも私は今行くべきことがあります。そして、もし誰かがこの質問に対する答えを知っていたら、それをコミットしてください! –

+0

関連するSEの質問を見てください:https://stackoverflow.com/questions/3269445/executorservice-how-to-wait-for-all-tasks-to-finish/ –

答えて

3

この種のスレッドタスクには、CompletableFutureを使用することをお勧めします。あなたは、このためのいくつかのライブラリを使用したい場合、私はアッカ(イベントドリブン)のようなものを探求することをお勧め

public class RunAfterNThreads { 

public static void main(String[] args) throws ExecutionException, InterruptedException { 
    CompletableFuture.supplyAsync(RunAfterNThreads::runFirstBatchOfThreads) 
      .thenAcceptAsync((t) -> runSecondBatchOfThreads(null)).get(); 
} 

private static Object runSecondBatchOfThreads(Object something) { 
    return something; 
} 

private static <U> U runFirstBatchOfThreads() { 
    return null; 
} 

}

:それはこのようになります。

+0

あなたの例をありがとう!基本的には、CompletableFutureについての知識があれば、私はコールバックをseparetelyで学習する必要はありません。 –

+0

@MoraMisina私はちょうどこの小さなビットで遊ぶと言うでしょう。違いを学び、ユースケースを解決するためのよりよい方法を学びます。 – mdev

3

ちょうどあなたが匿名Runnableインスタンス内にそれを参照するために、最終的なようcdlを宣言する必要があるかもしれませんCountDownLatch

第三 Runnable内部
executor.submit(new Runnable() { 
    public void run() { 
     cdl.await(); //will wait until both methods are complete 
     result(); //simulation of a method that needs previous threads to execute } 
    }); 
} 

待つ:

final CountDownLatch cdl = new CountDownLatch(2); //count of 2 

代替アプローチを

持っていますcreatするメソッドe 3番目のタスクは次のようになります。

void createThirdTask() { 
    executor.submit(new Runnable() { 
     public void run() { 
      result(); //simulation of a method that needs previous threads to execute } 
     }); 
    } 
} 

最初の2つのタスクとカウンタの間に共有ロックが1つあります。

private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 
private int count = 2; 

method1()内側とCDLのmethod2()減少値と、それがゼロに達した場合は第三タスクを発射。

void method1() { 
     //your actual code goes here 
    try { 
     lock.writeLock().lock(); 
     if(count-- == 0) { 
      createThirdTask(); 
     } 
    } finally { 
     lock.writeLock().unlock() 
    } 
} 

ReentrantReadWriteLockは競合状態を防止するためのものです。

+0

ありがとう、あなたのコメントをいただきありがとうございます。しかし、CDLを使用せずにsimmilarなことをする良い方法はありますか? –

+0

このメソッドはExecutorサービスの 'Thread'を使用していないので、より多くのスレッドが必要ですか? –

+0

@MoraMisina:この方法で 'CountDownLatch'を使うのはどうですか? – rkosegi

2

Javaに本当に良い標準メカニズムがあるかどうかはわかりません。 Eclipseの内部コードには、タスクとその依存関係を処理するための余分なクラスがあります。

はしかし、私はあなたがそうすることをCompletableFuture「使用」することができるかもしれないと思う:あなたの状況はより複雑である場合

import java.util.concurrent.CompletableFuture; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Main { 
    public static void main(String[] args) { 
     ExecutorService executor = Executors.newCachedThreadPool(); 
     Runnable r1 =() -> System.out.println("runnable 1"); 
     Runnable r2 =() -> System.out.println("runnable 2"); 
     Runnable r3 =() -> System.out.println("runnable 3"); 


     CompletableFuture<Void> cf1 = CompletableFuture.runAsync(r1, executor); 
     CompletableFuture<Void> cf2 = CompletableFuture.runAsync(r2, executor); 

     cf1.runAfterBoth(cf2, r3); 
    } 
} 

あなたは「有向非巡回グラフの」タスクのライブラリーを探したほうが良いかもしれません。

+0

基本的に、CompletableFutureは正しくサポートしていればアップグレードされたコールバックです。 –

+0

Javaが提供するクラスではないパターンなので、「コールバック」が何を意味するのかよく分かりません。たぶん[このブログ](http://www.baeldung.com/java-completablefuture)は、 'CompletableFuture'について学ぶのに役立つかもしれません。 –

+0

ちょっと別のこと:CompletableFutureは、完了するために単一のスレッドを待つための「最適な」メソッドです。 –