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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33845405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:04:46  来源:igfitidea点击:

How to check if all tasks running on ExecutorService are completed

javamultithreadingexecutorservice

提问by user4129715

I'v got ConcurrentLinkedDeque which I'm using for synchronic push/pop elements, and I'v got some async tasks which are taking one element from stack and if this element has neighbors It's pushing it to stack.

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

Example code:

示例代码:

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)
                }
             } 
         }
    }

I would like to have additional statement in while loop which answers the question - "any task in Executor is working?"

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

采纳答案by Andy Guibert

There isn't a clean way to check if all Runnables are done if you use ExecutorService.execute(Runnable). Unless you build a mechanism to do so in the Runnable itself (which is sloppy in my opinion).

如果您使用ExecutorService.execute(Runnable). 除非您在 Runnable 本身中构建了一个机制来这样做(在我看来这很草率)。

Instead:
Use ExecutorService.submit(Runnable). This method will return a Future<?>which is a handle to the result of a Runnable. Using Futures provides a clean way to check results.

相反:
使用ExecutorService.submit(Runnable). 此方法将返回 a Future<?>,它是 a 的结果的句柄Runnable。使用 Futures 提供了一种干净的方法来检查结果。

All you have to do is maintain a list of Futures that you submit, and then you can iterate over the whole list of Futures and either:
  A) wait for all the futures to be done in a blocking way or
  B) check if all the futures are done in a non-blocking way.

您所要做的就是维护您提交的期货列表,然后您可以遍历整个期货列表,并且:
  A)等待所有期货以阻塞方式完成或
  B)检查是否所有期货期货以非阻塞方式完成。

Here is a code example:

这是一个代码示例:

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
}

回答by Carlos Sanchez

Update: with Java 8+ CompletableFutures you can manage this with its new callback functions. First you will need to create all of the CompletableFutures you need which will also start running, eg:

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

We need to accumulate all the futures generated in an Array in order to pass them later to CompletableFuture.allOf(CompletableFutures...)

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

So let's say you have a list of people you want to calculate its days until birthday asynchronously:

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

First we create all those needed futures and collect them together in an array:

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

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

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

Then you pass those completables to a new CompletableFuture:

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

CompletableFuture c = CompletableFuture.allOf(completables)

And you can now check if there are still futures running with:

您现在可以检查是否仍有期货在运行:

c.isDone()