问题描述
我已将 FutureTask
从 java.util.concurrent
中扩展,以提供回调来跟踪提交的任务的执行到 ExecutorService
。
I've extended FutureTask
from java.util.concurrent
to provide callbacks to track the execution of tasks submitted to an ExecutorService
.
public class StatusTask<V> extends FutureTask<V> {
private final ITaskStatusHandler<V> statusHandler;
public StatusTask(Callable<V> callable, ITaskStatusHandler<V> statusHandler){
super(callable);
if (statusHandler == null)
throw new NullPointerException("statusHandler cannot be null");
this.statusHandler = statusHandler;
statusHandler.TaskCreated(this);
}
@Override
public void run() {
statusHandler.TaskRunning(this);
super.run();
}
@Override
protected void done() {
super.done();
statusHandler.TaskCompleted(this);
}
}
现在,我看到的是if任务被提交,但最终排队,并且i cancel(true);
任务 - run()
仍然被调用 - 并且 FutureTask.run()
(可能)检查任务是否被取消,并且不调用被包装的可调用方。
Now, what I see is if the task is submitted, but ends up queued and i cancel(true);
the task - the run()
method still gets called - and the FutureTask.run()
(likely) checks that the task is cancelled and doesn't call the wrapped callable.
我应该做eg
@Override
public void run() {
if(!isCancelled()) {
statusHandler.TaskRunning(this);
super.run();
}
}
super.run()?
Or should I still call super.run()
? Both these approaches seems susceptible to race conditions in between checking for cancellation and doing something about it.. any thoughts appreciated.
推荐答案
您可以使用这些方法是的,那里有一场比赛。 FutureTask#done()
将最多调用一次 ,因此如果任务在通过<$ c $运行之前已被取消c> RunnableFuture#run(),您将错过对 FutureTask#done()
的调用。
You're right that there's a race there. FutureTask#done()
will be called at most once, so if the task has already been canceled before it was ever run via RunnableFuture#run()
, you'll have missed the call to FutureTask#done()
.
你考虑过一个更简单的方法,它总是对 ITaskStatusHandler#taskRunning()
和发出一个对称的成对调用。ITaskStatusHandler#
Have you considered a simpler approach that always issues a symmetric set of paired calls to ITaskStatusHandler#taskRunning()
and ITaskStatusHandler#taskCompleted()
, like so?
@Override
public void run() {
statusHandler.TaskRunning(this);
try {
super.run();
finally {
statusHandler.TaskCompleted(this);
}
}
一次 RunnableFuture#run )
被调用,这是真的,你的任务在运行,或至少试图运行。一旦 FutureTask#run()
完成,您的任务就不再运行。
Once RunnableFuture#run()
is called, it's true that your task in running, or at least trying to be run. Once FutureTask#run()
is done, your task is no longer running. It so happens that in the case of cancellation, the transition is (nearly) immediate.
尝试避免调用 ITaskStatusHandler#taskRunning()
Trying to avoid calling ITaskStatusHandler#taskRunning()
if the inner Callable
or Runnable
is never invoked by FutureTask#run()
will require you to establish some shared structure between the Callable
or Runnable
and the FutureTask
-derived type itself, so that when your inner function is first called you set some flag that the outer FutureTask
-derived type can observe as a latch, indicating that yes, the function did start running before having been canceled. However, by then, you had to have committed to calling ITaskStatusHandler#taskRunning()
, so the distinction isn't so useful.
我最近一直在努力处理类似的设计问题,并且在我重写的之前和 > FutureTask#run()方法。
I've been struggling with a similar design problem lately, and wound up settling on the symmetric before and after operations in my overridden FutureTask#run()
method.
这篇关于扩展FutureTask,如何处理取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!