如何检查在 ExecutorService 上运行的所有任务是否已完成

新手上路,请多包涵

我有 ConcurrentLinkedDeque 用于同步推送/弹出元素,我有一些异步任务从堆栈中取出一个元素,如果这个元素有邻居,它会将它推入堆栈。

示例代码:

 private ConcurrentLinkedDeque<Item> stack = new ConcurrentLinkedDeque<>();
private ExecutorService exec = Executors.newFixedThreadPool(5);

    while ((item = stack.pollFirst()) != null) {
                if (item == null) {
                } else {
                    Runnable worker = new Solider(this, item);
                    exec.execute(worker);
                }
            }

   class Solider{
         public void run(){
             if(item.hasNeighbors){
                for(Item item:item.neighbors){
                    stack.push(item)
                }
             }
         }
    }

我想在 while 循环中有额外的语句来回答这个问题——“Executor 中的任何任务都在工作吗?”

原文由 user4129715 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 869
2 个回答

如果您使用 ExecutorService.execute(Runnable) ,则没有一种干净的方法来检查是否所有 Runnable 都已完成。除非你在 Runnable 本身中建立一个机制来这样做(我认为这很草率)。

反而:

使用 ExecutorService.submit(Runnable) 。此方法将返回 Future<?>Runnable 结果的句柄。使用 Futures 提供了一种检查结果的简洁方法。

您所要做的就是维护您提交的 Futures 列表,然后您可以遍历整个 Futures 列表,并且:

A)等待所有期货以阻塞方式完成或

B)检查是否所有期货都以非阻塞方式完成。

这是一个代码示例:

 List<Future<?>> futures = new ArrayList<Future<?>>();
ExecutorService exec = Executors.newFixedThreadPool(5);

// Instead of using exec.execute() use exec.submit()
// because it returns a monitorable future
while((item = stack.pollFirst()) != null){
    Runnable worker = new Solider(this, item);
    Future<?> f = exec.submit(worker);
    futures.add(f);
}

// A) Await all runnables to be done (blocking)
for(Future<?> future : futures)
    future.get(); // get will block until the future is done

// B) Check if all runnables are done (non-blocking)
boolean allDone = true;
for(Future<?> future : futures){
    allDone &= future.isDone(); // check if future is done
}

原文由 Andy Guibert 发布,翻译遵循 CC BY-SA 4.0 许可协议

更新:使用 Java 8+ CompletableFutures,您可以使用其新的回调函数来管理它。首先,您需要创建所有您需要的 CompletableFutures,它们也将开始运行,例如:

我们需要累积数组中生成的所有期货,以便稍后将它们传递给 CompletableFuture.allOf(CompletableFutures…)

因此,假设您有一个要异步计算生日前天数的人员列表:

首先,我们创建所有需要的期货并将它们收集在一个数组中:

 CompletableFuture<?>[] completables = people.stream()
    .map(p -> createCompletableFuture(p))
    .toArray(CompletableFuture<?>[]::new);

private CompletableFuture createCompletableFuture(Person p) {
        return CompletableFuture.runAsync(daysUntillBirthday(p));
    }

然后将这些可完成项传递给一个新的 CompletableFuture:

 CompletableFuture c = CompletableFuture.allOf(completables)

你现在可以检查是否还有期货运行:

 c.isDone()

原文由 Carlos Sanchez 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题