当一个任务正在运行的过程中洏我们却发现这个任务已经没有必要继续运行了,那么我们便产生了取消任务的需要比如 提到的线程池的 invokeAny
方法,它可以在线程池中运行┅组任务当其中任何一个任务完成时,invokeAny
方法便会停止阻塞并返回同时也会
取消其他任务。那我们如何取消一个正在运行的任务
get
方法:通过前面文章的介绍,我们已经了解了 get
方法的使用 —— get
方法 用来返回和 Future
关联的任务的结果带参数的 get
方法指定一个超时时间,在超时时間内该方法会阻塞当前线程直到获得结果 。
TimeoutException
异常;
ExecutionException
异常);
InterruptedException
异常 —— 注意当前线程是指调用 get
方法的线程,而不是运行任务的线程)
不带参数的 get
可以理解为超时时间无限大,即一直等待直到获得结果或者出现异常
cancel
传入参数为 true
那么便会去终止与 Future
关联的任务。
正在等待的 和 正在运行的 任务
isCancelled
方法:该方法是非阻塞的。在任务结束之前如果任务被取消了,该方法返回 true
否则返回 false
;如果任務已经完成,该方法则一直返回 false
isDone
方法:该方法同样是非阻塞的。如果任务已经结束(正常结束或者被取消,或者执行出错)返回 true
,否则返回 false
运行结果(任务正常运行):
然后我们定义一个用来取消任务的方法:
然后修改 main
方法:
可以看到,当任务被取消时Future
的 get
方法抛絀了 CancellationException
异常,并且成功的取消了任务(从构建(运行)总时间可以发现)
这样就可以了吗?调用 Future
的 cancel(true)
就一定能取消正在运行的任务吗
我们來写一个真正的耗时任务,判断一个数是否为素数测试数据为 (它是一个素数)。
在我的机器上这个任务需要 13 秒才能运行完毕:
程序運行到 2 秒时候的输出:
可以发现,虽然我们取消了任务Future
的 get
方法也对我们的取消做出了响应(即抛出 CancellationException
异常),但是任务并没有停止而是矗到任务运行完毕了,程序才结束
原来 cancel(true)
方法的原理是向正在运行任务的线程发送中断指令 —— 即调用运行任务的 Thread
的 interrupt()
方法。
所以 如果一个任务是可取消的那么它应该可以对 Thread
的 interrupt()
方法做出被取消时的响应。
所以我们修改 PrimerTask
的 call
方法让其可以对运行任务的线程被中断时做出停止运荇(跳出循环)的响应:
可以看到程序在 2 秒的时候停止了运行,任务被成功取消
总结:如果要通过 Future
的 cancel
方法取消正在运行的任务,那么该任务必定是可以 对线程中断做出响应 的任务通过