6

I am learning how to use thread pools in Java using ExecutorService, here is an example I am working on:

public class Example {
    static class WorkerThread implements Runnable {
        private String command;

        public WorkerThread(String s) {
            this.command = s;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
            processCommand();
            System.out.println(Thread.currentThread().getName() + " End.");
        }

        private void processCommand() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        @Override
        public String toString() {
            return this.command;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("" + i);
            executor.execute(worker);
        }
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.SECONDS);
//        while (!executor.isTerminated()) {
//        }
        System.out.println("Finished all threads");
    }
}

I have two questions:

  1. How should I wait for the termination of an ExecutorService, should I use awaitTermination() or isTerminated() (it has been suggested that the latter is a wrong way to do it)?

  2. Are the Runnables correctly added to the executor or should I use submit() together with a Future<T> callback?

It probably depends on the context, so would you please explain (for both questions) when should I use each of the solutions mentioned.

syntagma
  • 23,346
  • 16
  • 78
  • 134
  • You can use both `awaitTermination()` to wait (It can throw an InterruptedException), and then `isTerminated()` in the catch block to check for successful termination. Future callbacks are used when you want to know whether an individual task has been processed yet. – Andrew Williamson Feb 10 '16 at 19:31

3 Answers3

2

This program is not waiting for the threads to terminate, the JVM is doing the waiting: The output I get is:

pool-1-thread-1 Start. Command = 0
pool-1-thread-2 Start. Command = 1
pool-1-thread-3 Start. Command = 2
pool-1-thread-4 Start. Command = 3
pool-1-thread-5 Start. Command = 4
Finished all threads
pool-1-thread-2 End.
pool-1-thread-1 End.
pool-1-thread-4 End.
pool-1-thread-1 Start. Command = 5
pool-1-thread-3 End.
pool-1-thread-2 Start. Command = 7
pool-1-thread-5 End.
pool-1-thread-4 Start. Command = 6
pool-1-thread-5 Start. Command = 9
pool-1-thread-3 Start. Command = 8
pool-1-thread-3 End.
pool-1-thread-5 End.
pool-1-thread-4 End.
pool-1-thread-1 End.
pool-1-thread-2 End.

You will notice that Finished all threads is not at the bottom. If you want to wait for all the threads to finish, use this:

public class Example {
    static class WorkerThread implements Runnable {
        private String command;

        public WorkerThread(String s) {
            this.command = s;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
            processCommand();
            System.out.println(Thread.currentThread().getName() + " End.");
        }

        private void processCommand() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        @Override
        public String toString() {
            return this.command;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
        for (int i = 0; i < 10; i++) {
            tasks.add(Executors.callable(new WorkerThread("" + i)));
        }
        executor.invokeAll(tasks);
        System.out.println("Finished all threads");
        // this merely terminates the ExecutorService, otherwise the JVM will never close.
        executor.shutdown();
        executor.awaitTermination(10L, TimeUnit.SECONDS);

    }
}

You will notice the correct output:

pool-1-thread-1 Start. Command = 0
pool-1-thread-5 Start. Command = 4
pool-1-thread-4 Start. Command = 3
pool-1-thread-3 Start. Command = 2
pool-1-thread-2 Start. Command = 1
pool-1-thread-3 End.
pool-1-thread-1 End.
pool-1-thread-5 End.
pool-1-thread-3 Start. Command = 5
pool-1-thread-2 End.
pool-1-thread-4 End.
pool-1-thread-2 Start. Command = 8
pool-1-thread-1 Start. Command = 7
pool-1-thread-5 Start. Command = 6
pool-1-thread-4 Start. Command = 9
pool-1-thread-1 End.
pool-1-thread-4 End.
pool-1-thread-3 End.
pool-1-thread-5 End.
pool-1-thread-2 End.
Finished all threads
K.Nicholas
  • 10,956
  • 4
  • 46
  • 66
1

Couple of ways to achieve it: (a) Call awaitTermination(long someTime, TimeUnit ....) inside while (!executor.isTerminated()). (b) Store all callable inside Collection object and call executor.invokeAll(....). This is going to wait till all task gets completed by executor service.

Java Guru
  • 466
  • 4
  • 12
1

1.How should I wait for the termination of an ExecutorService, should I use awaitTermination() or isTerminated() (it has been suggested that the latter is a wrong way to do it)?

  1. You can use awaitTermination() after shutdown() OR
  2. You can use invokeAll() on executor service by passing List of Runnable/Callable tasks OR
  3. You can use CountDownLatch

Have a look at related SE questions for more details:

How to wait for all threads to finish, using ExecutorService?

ExecutorService, how to wait for all tasks to finish

Waiting for all the threads to finish before shutting down the Executors

2.Are the Runnables correctly added to the executor or should I use submit() together with a Future callback?

  1. If you just want to run the command without waiting for the result, use Runnable
  2. If you want to check the result of task after execution, use Callable

If you use submit(), exceptions are hidden in framework and you have to take care of handling the exceptions properly.

Have a look at related SE questions:

Choose between ExecutorService's submit and ExecutorService's execute

difference between executor.submit and executor.execute in this code in Java?

Community
  • 1
  • 1
Aditya W
  • 652
  • 8
  • 20