Java线程池shutdown和shutdownNow的区别
结论
先说结论
- shutdown 标记关闭 + 会执行积压任务(因线程不足而放入queue里的) + 不打断正在执行的任务 + 之后不允许添加新任务
- shutdownNow = 标记关闭 + 不执行积压任务 + 打断(通过线程interrupt)正在执行的任务 + 之后不允许添加新任务
- 对于停不下来的任务只能等到任务结束, 此过程 isTerminating 返回 true, 可以使用 awaitTemination 阻塞地等到真正关闭
- 等所有任务都停止运行了才算是真正关闭, 此时 isTerminated 返回 true
- 对于 ScheduledThreadPoolExecutor, setExecuteExistingDelayedTasksAfterShutdownPolicy(默认是true)可以控制shutdown之后是否执行积压的一次性任务(通过execute/schedule生成的一次性任务)
介绍
在java中, 普通线程池通常使用 ExecutorService 接口, 具备调度能力的通常使用 ScheduledExecutorService(扩展了ExecutorService).
ExecutorService上有几个跟关闭线程池相关的方法.
- shutdown: 停止线程池, 但不打断(通过线程interrupt)正在执行的任务
- shutdownNow: 停止线程池, 会打断(通过线程interrupt)正在执行的任务并返回被打断的List<Runnable>
- isShutdown: 用于判断shutdown是否已经被调用过, 及时返回true也不代表线程池已经真正关闭了
- isTerminated: 用于判断线程池是否已经真正关闭
- awaitTermination: 等待线程池真正关闭
具体的实现类 ThreadPoolExecutor 上还有
- isTerminating: 是否正在关闭中
显然, 线程池的关闭是一个过程, 需要一些时间, 因为有一些任务正在执行, 并且无法被打断,调用shutdown了之后可能有任务还在继续执行, 不过可以保证的是肯定不会有新的任务加进来执行了.
因此需要结合shutdown/awaitTermination的组合才能确线程池真正关闭.
另外, 具体的实现类 ScheduledThreadPoolExecutor 上还有
- setContinueExistingPeriodicTasksAfterShutdownPolicy: 默认是false, 建议设置成false就好, 该属性用于控制shutdown了之后是否继续执行已存在的periodic tasks(周期性执行的任务, 通过 scheduleWithFixedRate/withFixedDelay 提交的任务), 这通常不是想要的, 除非需要很精细话控制整个shutdown流程, 需要用户手动cancel掉这些任务才能真正达到terminated.
- setExecuteExistingDelayedTasksAfterShutdownPolicy: 默认是true, 该属性用于控制shutdown了之后是否继续执行已存在的一次性任务(通过 execute/schedule 方法提交的任务).