等待 FutureTask 上的 cancel()
我想取消从 ThreadPoolExecutor 获取的 FutureTask,但我想确保线程池上的 Callable 已停止其工作。
如果我调用 FutureTask#cancel(false) 然后调用 get() (阻塞直到完成)我会得到 CancelledException。这个异常是立即抛出还是在任务停止执行后抛出?
I want to cancel a FutureTask that I get from a ThreadPoolExecutor but I want to be sure that Callable on the thread pool has stopped its work.
If I call FutureTask#cancel(false) and then get() (to block until completion) I get a CancelledException. Is this exception thrown immediately or after the task has stopped executing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
此答案通过检查任务是否已在可调用内部取消来修复 Aleksey 和 FooJBar 代码中的竞争条件。 (FutureTask.run 检查状态和运行可调用之间有一个窗口,在此期间 cancel 和 getWithJoin 都可以成功完成。但是,可调用仍将运行。)
我还决定不覆盖原始取消,因为新的取消取消需要声明InterruptedException。新的取消摆脱了其无用的返回值(因为
true
可以表示“任务尚未开始”、“任务已开始并且已经造成大部分损害”、“任务已开始”中的任何一个并将最终完成”)。对 super.cancel 的返回值的检查也消失了,因此,如果从不同的线程多次调用新的取消,它们都将等待任务完成。This answer fixes the race condition in Aleksey's and FooJBar's code by checking if the task has been cancelled inside the callable. (There is a window between when FutureTask.run checks state and runs the callable during which both cancel and getWithJoin can successfully complete. However, the callable will still run.)
I've also decided not to override the original cancel, since the new cancel needs to declare
InterruptedException
. The new cancel gets rid of its useless return value (sincetrue
can mean any one of "task has not started", "task has started and has already done most of its damage", "task has started and will eventually complete"). Gone also is the check ofsuper.cancel
's return value, so that if the new cancel is called multiple times from different threads, they will all wait for the task to complete.是的,
CancellationException
会立即抛出。您可以扩展 FutureTask 以添加get()
方法的版本,该版本会等待Callable
的线程完成。Yes,
CancellationException
is thrown immediately. You may extend FutureTask to addget()
method's version which waits untilCallable
's thread is finished.阿列克谢的例子很有效。我编写了一个变体,其构造函数采用 Runnable (将返回 null)并展示如何在 cancel() 上直接阻止(加入):
Aleksey's example works well. I wrote a variant with a constructor taking a Runnable (will return null) and showing how to directly block (join) on cancel():
一旦取消就会被抛出。
没有简单的方法可以知道它已经开始和结束。您可以为可运行对象创建一个包装器来检查其状态。
It is thrown as soon as it is cancelled.
There is no easy way to know it has started and is finished. You can create a wrapper for you runnable to check its state.
CompletionSerivce 比仅 FutureTask 更强大,并且在许多情况下它更合适。我从中得到一些解决问题的想法。另外,它的子类ExecutorCompletionService比FutureTask简单,只包含几行代码。很容易阅读。所以我修改该类以获得部分计算结果。毕竟,这对我来说是一个令人满意的解决方案,看起来简单明了。
CompletionService 可以确保我们从
take
或poll
方法获取的 FutureTask 已经完成。为什么?因为QueueingFuture
类,只调用了它的run
方法,没有调用cancel
等其他方法。换句话说,它正常完成。演示代码:
这是类代码:
CompletionSerivce is more powerful than only FutureTask and in many case it's more suitable. I get some ideas from it to solve the problem. Besides, its subclass ExecutorCompletionService is simple than FutureTask, just including a few lines code. It's easy to read. So I modify the class to get partly computed result. A satisfying solution for me, after all, it looks simple and clear.
CompletionService can ensure that the FutureTask have already been done we get from
take
orpoll
method. Why? Because theQueueingFuture
class, its methodrun
are called only, other methods such ascancel
was not called. In other words, It completes normally.Demo code:
This is the class code: