2

I need main thread to wait until all the thread pools task complete. How to do it? For eg: I have program:

  public static void main(String[] args){

        ExecutorService executor = Executors.newFixedThreadPool(2);
        Map<String,String> test = new HashMap<String,String>(){{
            put("a","b");
            put("c","b");

        }};
        for(String t: test.keySet()) {
            executor.execute(new Runnable() {
                public void run() {
                    for(int i=0;i<100;i++){
                        System.out.println("t = " + t);
                    }

                }
            })
            ;
        }

        executor.shutdown();

        System.out.println("outside");;
    }

In the above code, I want to print "outside" always at the last i.e. after completion of ExecutorService tasks.

Yashasvi Raj Pant
  • 1,274
  • 4
  • 13
  • 33

3 Answers3

1

When using an Executor, we can shut it down by calling the shutdown() or shutdownNow() methods. Although, it won’t wait until all threads stop executing. (That's why, in your code "outside" is printed first not last).
Waiting for existing threads to complete their execution can be achieved by using the awaitTermination() method which blocks the thread until all tasks complete their execution or the specified timeout is reached

change

executor.shutdown();

to

            executor.shutdown();
            try {
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException ex) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
Nitika Bansal
  • 740
  • 5
  • 10
1

The method you are looking for exactly is

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
                          throws InterruptedException

From the javadocs,

Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.

However, you will need to convert Runnable to List<Callable<Void>> to make use of this.

Also, I would use Timeouts for sanity when using the code in production, which has method signature of

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                            long timeout,
                            TimeUnit unit)
                          throws InterruptedException

for sanity!

Mohamed Anees A
  • 4,119
  • 1
  • 22
  • 35
  • This way, you also don't have to shutdown the executor (if you still need it for other things). – Thilo Jun 10 '19 at 09:22
0

You can use CountDownLatch instead of Executors. This is block a calling thread until it’s been counted down to zero. Or you can use CyclicBarrier. Main difference is CyclicBarrier can be reset and use again.

CounDownLatch vs CyclicBarrier.

Simple Example CounDownLatch.

Turac
  • 667
  • 1
  • 4
  • 19