我FutureTask已从java.util.concurrent提供回调来跟踪提交给的任务的执行ExecutorService。
FutureTask
java.util.concurrent
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); } }
现在,我看到的是任务是否已提交,但最终进入队列,并且cancel(true);任务run()仍被调用FutureTask.run()(方法仍然被调用),并且(可能)检查任务已取消且未调用包装的可调用对象。
cancel(true);
run()
FutureTask.run()
我应该做例如
@Override public void run() { if(!isCancelled()) { statusHandler.TaskRunning(this); super.run(); } }
还是应该打电话给我super.run()?在检查取消和对其进行任何操作之间,这两种方法似乎都容易受到比赛条件的影响。
super.run()
您说对了,那是对的。FutureTask#done()系统 最多 会调用 一次 ,因此如果任务在通过运行之前已被取消RunnableFuture#run(),您将错过对的呼叫FutureTask#done()。
FutureTask#done()
RunnableFuture#run()
您是否考虑过一种更简单的方法,该方法总是向ITaskStatusHandler#taskRunning()和发出对称的成对调用集ITaskStatusHandler#taskCompleted(),像这样?
ITaskStatusHandler#taskRunning()
ITaskStatusHandler#taskCompleted()
@Override public void run() { statusHandler.TaskRunning(this); try { super.run(); finally { statusHandler.TaskCompleted(this); } }
一旦RunnableFuture#run()被调用,您的任务确实正在运行,或者至少正在尝试运行。一旦FutureTask#run()完成,你的任务不再运行。碰巧在取消的情况下,过渡是(几乎)立即进行的。
FutureTask#run()
试图避免ITaskStatusHandler#taskRunning()如果内部Callable或Runnable从未被调用,FutureTask#run()则需要您在Callableor Runnable和- FutureTask派生类型本身之间建立一些共享结构,以便在首次调用内部函数时,设置一些标志,使外部FutureTask派生类型可以观察为锁存器,表明是的,该函数在取消 之前 确实开始运行。但是,到那时,您必须承诺要调用ITaskStatusHandler#taskRunning(),因此区别并不是那么有用。
Callable
Runnable
我一直在挣扎了类似的设计问题最近,彼时安定在对称的 前 和 手术后 我重写FutureTask#run()方法。