前言 最近在使用ExecutorService的时候,对于与ExecutorService相关的概念有些迷糊, 加上本身ExecutorService内部的有些方法名在取名上也容易让使用者误解,导致 犯了一些错误。在解决的过程中,偶尔看到了日本人写的一篇文章简单明了,通俗易懂 所以想着翻译成中文希望能够帮助到与我有一样困惑的程序员朋友们。 原文地址如下: http://gurimmer./daihakken/2012/01/27/javaexecutorserviceの正しい終了shutdownの仕方/ 闲话少说,文章如下
虽然使用ExecutorService可以让线程处理变的很简单, 我们用学校的老师和学生的关系来说明这个问题。
shutdown只是起到通知的作用
我们来假设如下场景:
上面的场景对应于ExecutorService里的方法的话是下面的样子。
“问题解答完毕后请举手示意!”是shutdown方法。“老师我做完了!”是各个任务(Runnable)的运行结束。
在这里,我们假设试卷中有难度较大的问题,当然学生解答较难的问题也会比较花时间。 这时如果即使授课时间结束(main线程结束),学校也不能放学(Java进程结束),因为学生们还在解题中呢。这个时候如果你是老师你会怎么做? 一般的情况肯定是经过一定的时间在授课快要结束的时候,如果还有人没有解答出来的话,或者公布给大家解题方法, 或者作为课后习题让学生回去继续思考,然后结束上课对不对!
定好下课时间后等待结束
如果经过了一定的时间任务(Runnable)还不结束的时候我们可以通过中止任务(Runnable)的执行,以防止一直等待任务的结束。
具体的使用方法是,在shutdown方法调用后,接着调用awaitTermination方法。这时只需要等待awaitTermination方法里第一个参数指定的时间。 通过shutdownNow方法,我们可以作为老师向同学发出“没有解答出来的同学明天给出解答”的命令后结束授课。
shutdownNow方法的作用是向所有执行中的线程发出interrupted以中止线程的运行。这时,各个线程会抛出InterruptedException异常(前提是 所以正确的中止线程的方法如下:
可以看出上面程序中waitTime的值比awaitTime大的情况下,发生Timeout然后执行中的线程会中止执行而结束。 在这里,如果我们把awaitTime和shutdownNow方法全部屏蔽掉的只留下shutdown方法的话会怎样呢?
会变成表示main方法结束的「end」显示出来之后,会打印出很多的task2的start和end。 所以我们一定不要忘记使用awaitTermination和shutdownNow
shutdown也是很重要的
看了上面的描述后可能有些人会认为,只需要执行awaitTermination和shutdownNow就可以正常结束线程池中的线程了。其实不然。 shutdown方法调用后,就不能再继续使用ExecutorService来追加新的任务了,如果继续调用execute方法执行新的任务的话 就会抛出RejectedExecutionException异常。(submit方法也会抛出上述异常) 而且,awaitTermination方法也不是在它被调用的时间点上简单得等待任务结束而是在awaitTermination方法调用后, 持续监视各个任务的状态以或者是否线程已经运行结束。所以不调用shutdown方法执行调用awaitTermination的话由于追加出来的任务可能 会导致任务状态监视出现偏差而发生预料之外的awaitTermination的Timeout异常
正确的调用顺序是
shutdown方法
实际开发的系统可能会有不能强制线程中止执行的场景出现,所以虽然推荐使用上面说的调用顺序但也并不是绝对一成不变的。 另外,可以经过一定时间间隔而有计划调用任务执行的ScheduledExecutorService同样适用于上面说的调用顺序,但是在使用scheduled方法的时候需要另外一些步骤。 |
|
来自: hongjing_z > 《线程》