等待所有任务完成

时间:2014-06-23 09:42:08

标签: java multithreading concurrency threadpool

我使用相同的线程池完成了一系列不同的“任务”。我想测量执行每项任务所需的时间,但为此我需要等待“任务”中的每项任务(抱歉模棱两可)才能完成。

如果只有一项任务,我通常会这样做:

ExecutorService e = Executors.newCachedThreadPool();
for (int i=0; i<100; ++i)
    e.submit(target);
e.shutdown();
while (!e.isTerminated());

但是由于将有几个任务提交到池中,我无法拒绝。所有与等待任务完成提及“关闭请求后”相关的方法。那么,如果我不想关闭它,但等待所有线程完成然后提交更多任务呢?

这就是我想要做的事情:

ExecutorService e = Executors.newCachedThreadPool();
for (int i=0; i<100; ++i)
    e.submit(target);
// wait for all targets to finish
for (int i=0; i<100; ++i)
    e.submit(target); // submit different tasks
// wait... and so on

我想要关闭游泳池,然后使用prestartAllCoreThreads再次“唤醒”,但后来我意识到这不是ExecutorService方法,而是ThreadPoolExecutor方法。这可能是一个解决方案吗?关闭它,等待,然后再次激活池?对我来说似乎有点难看。

我还认为最自然的事情是使用CyclicBarrier,但这似乎是一种特定的方式,而我认为能够使用任何一种方式是最合乎逻辑的。 ExecutorService我正在尝试做的事情。

有什么方法可以坚持ExecutorService并等待所有任务完成?

3 个答案:

答案 0 :(得分:2)

您可以等待ExecutorService终止。

    ExecutorService executor = Executors.newCachedThreadPool();    
   //do your stuff

    try {
        executor.shutdown();
        executor.awaitTermination(5, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        //handle
    }

或使用CountDownLatch

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

并在你的任务中(包含在try / finally中)

latch.countDown();

答案 1 :(得分:2)

使用CyclicBarrier进行所需的工作,如下所示:

// the optionalRunnable can collect the data gathered by the tasks
CyclicBarrier b = new CyclicBarrier(numberOfTasks,optionalRunnable)

Task yourTaks = new Task(...., b);
// inside the run method call b.await() after the work is done;
executor.submit(yourTaks);

或者,您也可以在主线程中调用await,并将屏障实例化为numTasks + 1。这样,您确定只有在完成处理当前批次后才能将任务重新提交给执行者

答案 2 :(得分:0)

您可以创建一个TaskListener接口,并将其传递给每个任务。每个任务在启动和停止时通知TaskListener。然后,您可以创建一个TimingTaskListener实现,该实现维护一个可以在以后查询的持续时间的ConcurrentMap。

public interface TaskListener {
   void onStart(String taskId);
   void onEnd(String taskId);
}

public class Task implements Runnable {
   private TaskListener taskListener;
   private String taskId;

   public Task(String taskId, TaskListener taskListener) {
      this.taskId = taskId;
      this.listener = listener;
   }

   public void run() {
      listner.onStart(taskId);
      try {
         doStuff();
      } finally {
         listener.onEnd(taskId);
      }
   }
}

// TODO: Implement TimingTaskListener to save durations to a ConcurrentMap
TimingTaskListener timingListener = new TimingTaskListener(); 
Runnable task1 = new Task("task1", timingListener);
Runnable task2 = new Task("task2", timingListener);

Future<?> f1 = e.submit(task1);
Future<?> f2 = e.submit(task2);

// futures block until the task is finished.
// You could also use a CountDownLatch to achieve the same
f1.get();
f2.get();

long time1 = timingListener.getDuration("task1");
long time2 = timingListener.getDuration("task2");