本文介绍了扩展FutureTask,如何处理取消的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已将 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,如何处理取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-09 03:56