如何优雅的关闭
Java
线程池
⾯试中经常会问到,创建⼀个线程池需要哪些参数啊,线程池的⼯作原理啊,却很少会问到线程池如何安全关闭的。
也正是因为⼤家不是很关注这块,即便是⼯作三四年的⼈,也会有因为线程池关闭不合理,导致应⽤⽆法正常
stop
的情况,还有出现⼀些报
错的问题。
本篇就以
ThreadPoolExecutor
为例,来介绍下如何优雅的关闭线程池。
01
线程中断
在介绍线程池关闭之前,先介绍下
Thread
的
interrupt
。
在程序中,我们是不能随便中断⼀个线程的,因为这是极其不安全的操作,我们⽆法知道这个线程正运⾏在什么状态,它可能持有某把锁,
强⾏中断可能导致锁不能释放的问题;或者线程可能在操作数据库,强⾏中断导致数据不⼀致混乱的问题。正因此,
JAVA
⾥将
Thread
的
stop
⽅法设置为过时,以禁⽌⼤家使⽤。
⼀个线程什么时候可以退出呢?当然只有线程⾃⼰才能知道。
所以我们这⾥要说的
Thread
的
interrrupt
⽅法,本质不是⽤来中断⼀个线程。是将线程设置⼀个中断状态。
当我们调⽤线程的
interrupt
⽅法,它有两个作⽤:
1
、如果此线程处于阻塞状态
(
⽐如调⽤了
wait
⽅法,
io
等待
)
,则会⽴马退出阻塞,并抛出
InterruptedException
异常,线程就可以通过捕获
InterruptedException
来做⼀定的处理,然后让线程退出。
2
、如果此线程正处于运⾏之中,则线程不受任何影响,继续运⾏,仅仅是线程的中断标记被设置为
true
。所以线程要在适当的位置通过调⽤
isInterrupted
⽅法来查看⾃⼰是否被中断,并做退出操作。
注:
如果线程的
interrupt
⽅法先被调⽤,然后线程调⽤阻塞⽅法进⼊阻塞状态,
InterruptedException
异常依旧会抛出。
如果线程捕获
InterruptedException
异常后,继续调⽤阻塞⽅法,将不再触发
InterruptedException
异常。
02
线程池的关闭
线程池提供了两个关闭⽅法,
shutdownNow
和
shuwdown
⽅法。
shutdownNow
⽅法的解释是:线程池拒接收新提交的任务,同时⽴马关闭线程池,线程池⾥的任务不再执⾏。
shutdown
⽅法的解释是:线程池拒接收新提交的任务,同时等待线程池⾥的任务执⾏完毕后关闭线程池。
以上的说法虽然没错,但是还有很多的细节,⽐如调⽤
shutdown
⽅法后,正在执⾏任务的线程做出什么反应?正在等待任务的线程⼜做出
什么反应?线程在什么情况下才会彻底退出。如果不了解这些细节,在关闭线程池时就难免遇到,像线程池关闭不了,关闭线程池出现报错
等情况。
再说这些关闭线程池细节之前,需要强调⼀点的是,调⽤完
shutdownNow
和
shuwdown
⽅法后,并不代表线程池已经完成关闭操作,它只是
异步的通知线程池进⾏关闭处理。如果要同步等待线程池彻底关闭后才继续往下执⾏,需要调⽤
awaitTermination
⽅法进⾏同步等待。
有了以上介绍,下⾯就结合线程池源码,分别说说这两个线程池关闭⽅法的⼀些实现细节。
shutdownNow
我们看⼀下
shutdownNow
⽅法的源码: