MST
星途 面试题库

面试题:Java线程池中如何优雅地停止线程池?

在Java线程池中,我们常常需要在合适的时机停止线程池。请描述 `shutdown()` 和 `shutdownNow()` 方法的区别,并举例说明在什么场景下应该使用 `shutdown()`,什么场景下应该使用 `shutdownNow()`。
49.7万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

shutdown()shutdownNow() 方法的区别

  1. shutdown()
    • 启动一个有序关闭,不再接受新任务,但会继续执行已提交的任务(包括已在队列中等待的任务)。
    • 调用该方法后,线程池状态变为 SHUTDOWN
    • 调用 shutdown() 后,isShutdown() 方法返回 true,但 isTerminated() 方法只有在线程池里所有任务都执行完毕后才返回 true
  2. shutdownNow()
    • 尝试停止所有正在执行的任务,停止处理等待队列中的任务,并返回等待执行的任务列表。
    • 调用该方法后,线程池状态变为 STOP
    • 它会向正在执行任务的线程发送 interrupt 中断信号,所以任务需要正确处理 InterruptedException 异常。

使用场景

  1. 使用 shutdown() 的场景
    • 当你希望在不再接受新任务的情况下,让线程池把已提交的任务全部执行完再关闭时使用。例如,一个日志处理线程池,在应用程序关闭时,希望确保所有已提交的日志记录任务都被处理完毕,避免日志丢失。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ShutdownExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int taskNumber = i;
            executorService.submit(() -> {
                System.out.println("Task " + taskNumber + " is running.");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("Task " + taskNumber + " is completed.");
            });
        }
        executorService.shutdown();
    }
}
  1. 使用 shutdownNow() 的场景
    • 当需要立即停止线程池,例如在紧急情况下,如系统出现严重错误需要马上关闭所有任务以释放资源时使用。比如,一个文件处理线程池,在检测到文件系统出现不可修复的错误时,需要立即停止所有文件处理任务。
import java.util.List;
import java.util.concurrent.*;

public class ShutdownNowExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            final int taskNumber = i;
            executorService.submit(() -> {
                System.out.println("Task " + taskNumber + " is running.");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("Task " + taskNumber + " is completed.");
            });
        }
        try {
            List<Runnable> tasks = executorService.shutdownNow();
            System.out.println("Tasks that were waiting to be executed: " + tasks.size());
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }
}