简体   繁体   中英

How to check if all tasks running on ExecutorService are completed

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.

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?"

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

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.

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.

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
}

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:

We need to accumulate all the futures generated in an Array in order to pass them later to 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 c = CompletableFuture.allOf(completables)

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

c.isDone()

This may not be the cleanest solution, but you can use ThreadPoolExecutor.getActiveCount() to check how many threads are actively executing tasks.

Implementing this within a while loop with a simple condition to check if the active thread count is zero is a palatable solution.

Here is a code example:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
    for (int x = 0; x < 4; x++) {
        Runnable worker = new Solider(this,item);
        executor.execute(worker);
    }
    // Now check for active threads.

    while(executor.getActiveCount()!=0)
    {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
executor.shutdown();

The while block directly answers your question. IE - If the while block is active, tasks are being executed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM