又被问到了:如何优雅关闭线程池?

137 阅读3分钟

年底了,柴宝准备出去看看机会,看看最近的后端开发市场环境,收到了大厂面试邀请…

几天后,柴宝碰见了大柴......

提到线程池的关闭得先了解下线程池的状态:

  • RUNNING:正常工作状态,在这个状态下,线程池接受新的任务并且处理已经提交的任务
  • SHUTDOWN:关闭状态,不能接受新的任务。此时,线程池会等待已提交的任务执行完毕(队列中),不会再接受新的任务。
  • STOP:停止状态,线程池中的所有任务都会被中断,线程池也不能接受新的任务。
  • TIDYING:清理中状态,其实是个过渡态,当线程池的所有任务都已经完成,线程池进入此状态。在这个状态下,线程池会执行清理工作,比如释放资源等
  • TERMINATED:结束状态,表示线程池已经完全终止,所有任务已经完成并且所有线程都已经退出,线程池不能再恢复

每个状态之间的转换:

总结:

  • RUNNING → SHUTDOWN:调用 shutdown()
  • RUNNING → STOP:调用 shutdownNow()
  • SHUTDOWN → TIDYING:所有任务完成,工作线程退出
  • TIDYING → TERMINATED:清理完成,线程池完全终止

线程池的关闭方法主要有三种:

(1)shutdown()

该方法用于优雅地关闭线程池。它会执行以下操作:

  • 不再接受新任务。
  • 等待所有已提交的任务执行完毕。
  • 线程池中的线程将继续执行队列中的任务,直到任务队列为空或所有任务执行完毕。

该方法不会立即停止正在执行的任务,也不会中断那些正在运行的线程。

(2)shutdownNow()

shutdownNow() 方法尝试立即停止线程池。它会执行以下操作:

  • 不再接受新任务。
  • 尝试停止正在执行的任务。
  • 返回一个列表,包含所有尚未开始执行的任务(这些任务将不会被执行)。

该方法试图通过中断正在执行的线程来停止任务,但不能保证任务立即终止,取决于任务本身是否响应中断。

(3)awaitTermination()

awaitTermination() 是用来配合 shutdown() 或 shutdownNow() 使用的,它会让当前线程(通常是主线程)等待直到线程池完全关闭或超时。该方法常用于确保线程池中的任务完成后再退出应用程序。

用法示例:

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {    
    try {        
        Thread.sleep(2000);        
        System.out.println("Task completed");    
    } catch (InterruptedException e){        
        Thread.currentThread().interrupt();    
    }});

executor.shutdown();  // 不再接受新任务

// 等待线程池中的任务完成或超时
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) 
{    
    System.out.println("Timeout: Forcefully shutting down the executor");    
    executor.shutdownNow();  // 如果超时,强制关闭线程池
}

  • awaitTermination()会让主线程等待,直到线程池中的所有任务完成,或者超时。
  • 通常配合 shutdown() 使用,确保线程池完全关闭后再继续程序执行。

(4)isShutdown() 和 isTerminated()

  • isShutdown() 方法返回一个布尔值,指示线程池是否已经关闭(即已调用 shutdown() 或 shutdownNow())
  • isTerminated() 方法返回一个布尔值,指示线程池是否已经完全终止(即所有任务都已完成或已被中断)

总结

  • 优雅关闭:使用 shutdown(),会等待已提交任务执行完成,不再接受新任务。

  • 强制关闭:使用 shutdownNow(),会尝试立即停止线程池,并返回未开始执行的任务。

  • 等待线程池完全关闭:使用 awaitTermination(),配合shutdown() 或 shutdownNow() 使用,可以等待线程池完全关闭或直到超时。

  • 检查线程池状态:使用 isShutdown() 和 isTerminated() 检查线程池的状态。

    在关闭线程池时,通常建议使用 shutdown() 方法,并配合 awaitTermination() 来确保线程池的优雅关闭。如果需要立即停止线程池中的任务,可以使用 shutdownNow()。