如何正确的关闭线程池
线程池是 Java 开发中常用的组件之一,在应用程序关闭的时候,需要将线程池关闭。但关闭线程池时,要按照不同的情况来使用不同的方式。下面介绍几种关闭线程池的常用方法。
💡本文基于 OpenJDK11
1. 线程池简介
Java 中的线程池都实现了 Executor
接口,这个接口提供了执行任务的入口。ExecutorService 继承了 Executor,提供了对线程池生命周期的管理,在开发中用的最多。
对于关闭线程池,ExecutorService 提供了三种方式:
shutdown
shutdownNow
awaitTermination
这几种方法都可以关闭线程池,但是每种方式之间有一些差别。
现有如下任务:
调用 shutdown
方法之后,线程池就不会再接收新的任务,如果强行添加,就会报错。而线程池中的任务会继续执行,但是却不保证这些任务能够执行完成,具体原因,下文会说到。
上面代码的执行结果如下:
调用 shutdownNow
方法之后,所以运行中的任务都会终止,而且会返回队列中等待的任务。
调用 awaitTermination
之后,线程池中的任务会继续运行,而且还可以接受新的任务。它是线程阻塞的,会等到任务执行完成才结束主线程,这是它与shutdown 的区别。当然也不会无限期的等下去,可以通过设置超时时间,在超时时间之后,就会结束线程的阻塞。
2. 正确的关闭线程池
执行简单任务
还以上面的 Task 为例,这种 Task 不依赖外部的数据,执行这种任务的线程池在关闭时,只需要调用 shutdown 方法即可。
这时程序的输出如下,任务会在主线程结束之后继续执行。
执行复杂任务
在执行一些复杂任务时,任务需要依赖外部的数据,任务为下:
在线程池中执行这个任务:
程序执行结果如下,在外部数据依赖删除之后,程序也就执行结束了。
如果这个依赖是一些网络连接,或者数据库连接,在主程序退出之后,这些连接就会被销毁,那么线程池中的任务就无法继续执行。所以这个时候需要阻塞主线程,给线程池中的任务一些执行的时间。
调用了 awaitTermination 方法之后,主线程就会被阻塞,等待线程池中的任务继续执行,但是也不会无限期的等下去,等待超时时间过了之后,主程序还是会退出。
在关闭线程池时,一般是 shutdown 与 awaitTermination 方法配合使用。
如果还想确认在线程池退出时,确保线程池中的任务全部结束,可以在阻塞时间过了之后使用 shutdownNow:
这样就可以让线程池按照预想的结果关闭。
文 / Rayjun
本文首发于微信公众号
版权声明: 本文为 InfoQ 作者【Rayjun】的原创文章。
原文链接:【http://xie.infoq.cn/article/268175fe9667ed1bf37983b87】。文章转载请联系作者。
评论