SoFunction
Updated on 2025-05-08

How to create and use ExecutorService in Java

1. What is ExecutorService?

ExecutorService is an advanced tool in Java for managing and executing multithreaded tasks. It can effectively manage the life cycle of threads and the execution of tasks, especially when it is necessary to handle a large number of concurrent tasks.

A vivid metaphor, ExecutorService is like a manager, you can hand over the task to it, it will create threads as needed and ensure that the task is executed as you ask.

In actual programming, you can avoid direct operation of threads through ExecutorService, which is usually safer and more efficient.

You can create an ExecutorService and tell it the task to be executed. The ExecutorService will create threads as needed and recycle the threads for reuse after the task is executed, which can save resources and improve performance.

Let's take a look at a simple example:

Suppose there is a task that needs to process a lot of data, you can create an ExecutorService and tell it how many tasks it wants to perform at the same time. ExecutorService automatically creates and manages threads based on the settings to ensure that these tasks can be executed concurrently without interfering with each other. This approach is easier than manually managing threads and can better utilize the computer's multi-core processing capabilities.

// Create a fixed-size thread pool, performing up to two tasks at the same timeExecutorService executor = (2);
// Submit two tasks to thread pool to execute(() -> {
    ("Task 1 is executing...");
    // Here is the specific code logic for task 1});
(() -> {
    ("Task 2 is executing...");
    // Here is the specific code logic for task 2});
// Close the thread pool();

2. The core functions of ExecutorService

Create a fixed-size thread pool

// Create a fixed-size thread pool with 5 threadsExecutorService executor = (5); 

Use scenarios:When it is necessary to limit the number of threads executed simultaneously, a fixed-size thread pool can be used. This can control the number of concurrent threads and avoid excessive consumption of system resources.

Create a cacheable thread pool

// Create a thread pool that can be automatically expanded as neededExecutorService executor = (); 

Use scenarios:When there are a large number of short-term asynchronous tasks to be processed, a cacheable thread pool can be used. It automatically creates new threads based on the addition of tasks and reuses existing threads when they are idle, thereby improving performance.

Submit Runnable Task

(() -> {
    ("Execute Task 1");
    // Here is the specific code logic for task 1});

Use scenarios:When you need to perform a simple task without a return value, you can submit the implementationRunnableInterface tasks. For example, asynchronous operations such as cleaning temporary files and sending notifications.

Submit Callable task and get results

Future<Integer> future = (() -> {
    ("Execute Task 2");
    // Here is the specific code logic for task 2    // Return the task execution result    return fu;  
});
try {
    // Get the task execution result, which may block until the task is completed    Integer result = ();  
    ("The result of Task 2 is:" + result);
} catch (InterruptedException | ExecutionException e) {
    ();
}

Use scenarios:When you need to execute a task with a return value and you may need to wait for the task to complete to get the result, you can submit the implementation.CallableInterface tasks and useFutureThe object gets the return value of the task.

Extensions:

The Future interface provides a special blocking methodget(), it returns the actual result of the Callable task execution, but if it is a Runnable task, it will only return null.

If calledget()When the method is still running, the call will be blocked until the task is correctly executed and the result is available.

get() The method is blocking and it is not known how long it will take to block. This may lead to a degradation in the performance of the application. If the result data is not important, then we can use the timeout mechanism to avoid long-term blocking.

// Wait for 200 millisecondsString result = (200, );

The overload of get(), the first parameter is the timeout time, and the second parameter is the unit of time.

Control the shutdown of thread pool

// Smoothly close the thread pool and wait for all tasks to complete(); 

Use scenarios:When ExecutorService is no longer needed, it should be calledshutdown()Method to close the thread pool. Ensure that the submitted tasks can be executed and avoid resource leakage and task loss problems.

3. How to create and use ExecutorService?

useExecutorsFactory class to create different types of ExecutorServices.

newFixedThreadPool(int n)A fixed-size thread pool can be created.

newCachedThreadPool()Then you can create a thread pool that automatically expands as needed.

Actual case:

Create a simple multithreaded program, use the ExecutorService to execute a batch of tasks, and get their execution results.

public static void main(String[] args) {
        // Create a thread pool with a fixed size of 3        ExecutorService executor = (3);
        // Create a list to save submitted tasks        List<Future<Integer>> futures = new ArrayList<>();
        // Submit 10 tasks, each task returns the result of multiplying the task ID by 2        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            // Submit Callable task and save the Future object to the list            Future<Integer> future = (() -> {
                ("Task " + taskId + "Start execution");
                // Time-consuming execution of simulation tasks                (2000);  
                // Return the result of the task                return taskId * 2;   
            });
            // Add the Future object to the list            (future);  
        }
        // Wait for all tasks to complete and print the execution results of each task        for (Future<Integer> future : futures) {
            try {
                // Get the task execution result, which may block until the task is completed                Integer result = ();  
                ("Task Results: " + result);
            } catch (InterruptedException | ExecutionException e) {
                ();
            }
        }
        // Close the thread pool        ();
    }
// Output resultTask 1 Start execution
Task 2 Start execution
Task 3 Start execution
Task结果: 2
Task结果: 4
Task 4 Start execution
Task结果: 6
Task 5 Start execution
Task结果: 8
Task 6 Start execution
Task结果: 10
Task 7 Start execution
Task结果: 12
Task 8 Start execution
Task结果: 14
Task 9 Start execution
Task结果: 16
Task 10 Start execution
Task结果: 18
Task结果: 20

Time cannot add to a person's life, but cherishing time can make life more valuable

This is all about this article about Java ExecutorService. For more related Java ExecutorService content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!