これは、次の場合の理想的な使用例のように思えますExecutorService.invokeAll
。
ExecutorService pool = Executors.newCachedThreadPool();
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
for(int i = 0; i < myList.size(); ++i) {
tasks.add (Executors.callable(new ThreadProcessRunnable (args)));
}
List<Future<Object>> futures = pool.invokeAll(tasks);
System.out.println("All tasks finished");
public class ThreadProcessRunnable implements Runnable {
public void run() {
// do some stuff
}
}
invokeAll
提供されたすべてのタスクが完了するまでブロックList
します。
println
スレッドのメソッドの内部にどうしても必要な場合は、run
私が考えることができる最も簡単な方法は、ある種のカウンターをAtomicInteger
public class ThreadProcessRunnable implements Runnable {
private AtomicInteger taskCounter;
public ThreadProcessRunnable(AtomicInteger counter) {
this.taskCounter = counter;
}
public void run() {
// do stuff
if(taskCounter.decrementAndGet() == 0) {
System.out.println("I am the last thread and I am about to finish");
}
}
}
// Main class
ExecutorService pool = Executors.newCachedThreadPool();
AtomicInteger taskCounter = new AtomicInteger(myList.size());
for(int i = 0; i < myList.size(); ++i) {
pool.execute(new ThreadProcessRunnable(taskCounter));
}
この作業を行う重要な点は、アトミックであることtaskCounter.decrementAndGet
です。taskCounter
たとえば、の値が最初は 2 で、2 つの異なるスレッドdecrementAndGet
が同時に呼び出すと、一方のスレッドが値 1 を認識し、もう一方のスレッドが値を認識することが保証されます。値が 0 であるため、正確に 1 つのスレッドが「終了しようとしています」というメッセージを出力します。これは、競合状態を伴うMadProgrammer の answerとは異なります。
latch.countDown();
if(latch.getCount() == 0) { ... }
スレッド 1 が値を (1 に) デクリメントし、スレッド 2 が再び (0 に) デクリメントすると、両方のスレッドが呼び出し時に値 0 を認識し、メッセージが出力されます。getCount