What is the difference between closing a thread pool shutdown and shutdownNow?

Preface

This chapter is divided into two topics

  • How to Close Thread Pool Correctly
  • The difference between shutdown and shutdownNow

1. Thread pool example

public class ShutDownThreadPoolDemo {

    private ExecutorService service = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) {
        new ShutDownThreadPoolDemo().executeTask();
    }
    
    public void executeTask() {
        for (int i = 0; i < 100; i++) {
            service.submit(() -> {
                System.out.println(Thread.currentThread().getName() + "->implement");
            });
        }
    }

}

results of enforcement

pool-1-thread-2->implement
pool-1-thread-3->implement
pool-1-thread-1->implement
pool-1-thread-4->implement
pool-1-thread-5->implement
pool-1-thread-6->implement
...

Scanning VX for Java, Front End, Testing, python, etc.

After execution is complete, the main thread will always be blocked, so how do you close the thread pool? This chapter describes five ways to close a thread pool in ThreadPoolExecutor, as follows

  • void shutdown
  • boolean isShutdown
  • boolean isTerminated
  • boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
  • ListshutdownNow

2.shutdown

The first method is called shutdown(), which safely closes a thread pool. When the shutdown() method is called, the thread pool is not closed immediately, because there may be many tasks in the thread pool being executed or a large number of tasks waiting to be executed in the task queue. When the shutdown() method is called, the thread pool will not shut down completely until the executing task and the waiting task in the queue have been executed.

If new tasks are committed after the shutdown() method is called, the thread pool will reject subsequent newly committed tasks directly according to the rejection policy.

This source location (jdk version 1.8)

java.util.concurrent.ThreadPoolExecutor#execute

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // Fewer threads in the thread pool than core threads 
    if (workerCountOf(c) < corePoolSize) {
        // Create a new core thread to perform tasks
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // Core thread full, but task queue not full, added to queue
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // After the task has been successfully added to the queue, check again if a new thread needs to be added, as the existing thread may be destroyed
        if (! isRunning(recheck) && remove(command))
            // If the thread pool is not running and the current task is successfully removed from the task queue, the task is rejected
            reject(command);
        else if (workerCountOf(recheck) == 0)
            // If the previous thread has been destroyed, create a new non-core thread
            addWorker(null, false);
    }
    // Core thread pool full, queue full, try to create a new non-core thread
    else if (!addWorker(command, false))
        // If the creation of a new thread fails, the thread pool closes or the thread pool is full and the task is rejected
        reject(command);
}

Line 1373 if (! IsRunning (recheck) & & remove (command)) If the thread pool is closed, remove the current task from the task queue successfully and reject it

Line 1378 else if (!addWorker(command, false)) If the creation of a new thread fails, the thread pool closes or the thread pool is full and the task is rejected.

3.isShutdown

The second method, isShutdown(), returns true or false to determine if the thread pool has started shutting down, that is, whether the shutdown or shutdownNow method has been executed.

It is important to note that if the isShutdown() method is called and returns true, it does not mean that the thread pool has been completely closed at this time, it just means that the thread pool has started the process of closing, that is, there may still be threads in the thread pool performing tasks, or there may be tasks in the queue waiting to be executed.

4.isTerminated

The third method, isTerminated(), detects whether the thread pool is really "terminated", not only because it is closed, but also because all tasks in the thread pool have been executed.

For example, as we mentioned above, if the shutdown method has been called at this time, but there are still tasks not finished, then calling the isShutdown method returns true and the isTerminated method returns false.

A call to the isTerminated() method does not return true until all tasks have been executed, which means that the thread pool is closed and the interior of the thread pool is empty, and that all remaining tasks have been executed.

5.awaitTermination

The fourth method, called awaitTermination(), is not intended to close the thread pool itself, but rather to determine its state.

For example, if the parameter we passed in to the awaitTermination method is 10 seconds, it will be stuck waiting for 10 seconds until one of three things happens:

The thread pool has been closed during the wait period (including before entering the wait state) and all submitted tasks (including executing and queued waiting) have been executed, which is equivalent to the thread pool being "terminated", and the method will return true after the wait timeout expires, the first thread pool being "terminated" This never happens, the thread is interrupted while the method returns a false wait, and the method throws an InterruptedException exception. After calling the awaitTermination method, the current thread attempts to wait for a specified time. If the thread pool is closed and the internal tasks are completed within the wait time, that is, the thread pool is really "terminated". The method then returns true, otherwise it timed out to return fasle.

6.shutdownNow

The last method is shutdownNow(), which differs from shutdown() by adding one more Now, meaning immediate shutdown, which is not recommended for closing thread pools.

After executing the shutdownNow method, an interrupt interrupt signal is first sent to all threads in the thread pool to attempt to interrupt the execution of these tasks. Then all tasks waiting in the task queue are transferred to a List and returned. We can perform remedial actions based on the returned task List, such as logging and retrying later.

The shutdownNow source code is as follows:

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

interruptWorkers

Interrupt each thread that has been started so that the thread can detect interrupt signals and process them accordingly to end the task ahead of time

7. The difference between shutdown and shutdownNow?

  • shutdown waits for the execution of tasks in the thread pool to complete before closing the thread pool, and shutdownNow sends an interrupt signal to all threads, interrupts task execution, and then closes the thread pool
  • Shutdown does not return a value, and shutdownNow returns a List of tasks that were not executed in the task queue before shutdown

    Scanning VX for Java, Front End, Testing, python, etc.

Keywords: Java server Singleton pattern

Added by sklein99 on Mon, 13 Dec 2021 21:06:43 +0200