Java ThreadPoolExecutor awaitTermination() Method

The ThreadPoolExecutor class in Java provides the awaitTermination() method to wait for the completion of all tasks in the executor after a shutdown request. This guide will cover the usage of the awaitTermination() method, explain how it works, and provide concise examples to demonstrate its functionality in real-world use cases.

Introduction

The awaitTermination() method is used to block the calling thread until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first. It is typically used in conjunction with shutdown() or shutdownNow() to ensure that the executor has completed all its tasks before proceeding.

awaitTermination Method Syntax

The syntax for the awaitTermination method is as follows:

public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
  • The method takes two parameters:
    • timeout - the maximum time to wait.
    • unit - the time unit of the timeout argument.
  • The method returns a boolean value:
    • true if the executor terminated within the given timeout.
    • false if the timeout elapsed before termination.
  • The method throws InterruptedException if the current thread is interrupted while waiting.

Examples

Example 1: Basic Usage with Shutdown

In this example, we create a ThreadPoolExecutor, submit tasks to it, shut it down, and use awaitTermination() to wait for the completion of all tasks.

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AwaitTerminationExample {
    public static void main(String[] args) {
        // Create a ThreadPoolExecutor with 2 threads
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

        // Submit tasks to the executor
        for (int i = 0; i < 5; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shut down the executor
        executor.shutdown();

        try {
            // Wait for all tasks to complete or timeout after 10 seconds
            if (executor.awaitTermination(10, TimeUnit.SECONDS)) {
                System.out.println("All tasks completed successfully.");
            } else {
                System.out.println("Timeout elapsed before termination.");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Output:

Executing task 1 by pool-1-thread-1
Executing task 2 by pool-1-thread-2
Executing task 3 by pool-1-thread-1
Executing task 4 by pool-1-thread-2
Executing task 5 by pool-1-thread-1
Task 1 completed by pool-1-thread-1
Task 2 completed by pool-1-thread-2
Task 3 completed by pool-1-thread-1
Task 4 completed by pool-1-thread-2
Task 5 completed by pool-1-thread-1
All tasks completed successfully.

Example 2: Handling InterruptedException

In this example, we demonstrate how to handle the InterruptedException that might be thrown by the awaitTermination() method.

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class HandleInterruptedExceptionExample {
    public static void main(String[] args) {
        // Create a ThreadPoolExecutor with 2 threads
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

        // Submit tasks to the executor
        for (int i = 0; i < 5; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shut down the executor
        executor.shutdown();

        try {
            // Wait for all tasks to complete or timeout after 10 seconds
            if (executor.awaitTermination(10, TimeUnit.SECONDS)) {
                System.out.println("All tasks completed successfully.");
            } else {
                System.out.println("Timeout elapsed before termination.");
            }
        } catch (InterruptedException e) {
            System.err.println("Thread was interrupted while waiting for termination.");
            e.printStackTrace();
        }
    }
}

Output:

Executing task 1 by pool-1-thread-1
Executing task 2 by pool-1-thread-2
Executing task 3 by pool-1-thread-1
Executing task 4 by pool-1-thread-2
Executing task 5 by pool-1-thread-1
Task 1 completed by pool-1-thread-1
Task 2 completed by pool-1-thread-2
Task 3 completed by pool-1-thread-1
Task 4 completed by pool-1-thread-2
Task 5 completed by pool-1-thread-1
All tasks completed successfully.

Example 3: Combining shutdownNow() with awaitTermination()

In this example, we combine shutdownNow() with awaitTermination() to handle scenarios where we want to stop executing tasks immediately and wait for the completion of currently running tasks.

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ShutdownNowExample {
    public static void main(String[] args) {
        // Create a ThreadPoolExecutor with 2 threads
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

        // Submit tasks to the executor
        for (int i = 0; i < 5; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(2000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shut down the executor immediately
        List<Runnable> notExecutedTasks = executor.shutdownNow();
        System.out.println("Tasks not executed: " + notExecutedTasks.size());

        try {
            // Wait for all currently running tasks to complete or timeout after 5 seconds
            if (executor.awaitTermination(5, TimeUnit.SECONDS)) {
                System.out.println("All running tasks completed successfully.");
            } else {
                System.out.println("Timeout elapsed before termination.");
            }
        } catch (InterruptedException e) {
            System.err.println("Thread was interrupted while waiting for termination.");
            e.printStackTrace();
        }
    }
}

Output:

Executing task 1 by pool-1-thread-1
Executing task 2 by pool-1-thread-2
Tasks not executed: 3
Task 1 completed by pool-1-thread-1
Task 2 completed by pool-1-thread-2
All running tasks completed successfully.

Conclusion

The ThreadPoolExecutor.awaitTermination() method in Java is used for waiting for the completion of all tasks in the executor after a shutdown request. By using this method, you can ensure that your application properly waits for task completion before proceeding, helping to manage resources and maintain application stability.

Comments