当前位置: 首页 > 面试题库 >

扩展FutureTask,如何处理取消

方斌
2023-03-14
问题内容

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()(方法仍然被调用),并且(可能)检查任务已取消且未调用包装的可调用对象。

我应该做例如

@Override
public void run() {
  if(!isCancelled()) {  
    statusHandler.TaskRunning(this);
    super.run();
  }
}

还是应该打电话给我super.run()?在检查取消和对其进行任何操作之间,这两种方法似乎都容易受到比赛条件的影响。


问题答案:

您说对了,那是对的。FutureTask#done()系统 最多 会调用 一次
,因此如果任务在通过运行之前已被取消RunnableFuture#run(),您将错过对的呼叫FutureTask#done()

您是否考虑过一种更简单的方法,该方法总是向ITaskStatusHandler#taskRunning()和发出对称的成对调用集ITaskStatusHandler#taskCompleted(),像这样?

@Override
public void run() {
  statusHandler.TaskRunning(this);
  try {
    super.run();
  finally {
    statusHandler.TaskCompleted(this);
  }
}

一旦RunnableFuture#run()被调用,您的任务确实正在运行,或者至少正在尝试运行。一旦FutureTask#run()完成,你的任务不再运行。碰巧在取消的情况下,过渡是(几乎)立即进行的。

试图避免ITaskStatusHandler#taskRunning()如果内部CallableRunnable从未被调用,FutureTask#run()则需要您在Callableor
Runnable和-
FutureTask派生类型本身之间建立一些共享结构,以便在首次调用内部函数时,设置一些标志,使外部FutureTask派生类型可以观察为锁存器,表明是的,该函数在取消
之前 确实开始运行。但是,到那时,您必须承诺要调用ITaskStatusHandler#taskRunning(),因此区别并不是那么有用。

我一直在挣扎了类似的设计问题最近,彼时安定在对称的 手术后 我重写FutureTask#run()方法。



 类似资料:
  • 我有自定义的ExecutorService,其中包含一个可用于中断提交给ExecutorSerice的任务,如果他们花了太长时间,我把完备类放在这篇文章的末尾。 这工作正常,除了有时中断本身会引起问题,所以我把一个不稳定的布尔取消标志添加到一个新的CanceableWork类中,并把它们子类为this,这样它们就可以检查并停止自己,如果它们的布尔值已经被删除了发送到真实。请注意,它们是提交给执行器

  • 问题内容: 我的Go Web应用程序中有一个相当快捷的错误处理程序,它会引发HTTP错误,记录响应的重要部分并提供错误模板。我想删除在处理程序中多次编写类似代码的重复: 我已经阅读了Error Handling and Go文章,其中定义了一个自定义HTTP处理程序类型,该类型将返回这样的错误类型/结构(甚至返回int,err): 但是我不确定如何保留现有的中间件功能/包装,使我可以像这样链接中间

  • 很多批处理问题都可以通过单进程、单线程的工作模式来完成, 所以在想要做一个复杂设计和实现之前,请审查你是否真的需要那些超级复杂的实现。 衡量实际作业(job)的性能,看看最简单的实现是否能满足需求: 即便是最普通的硬件,也可以在一分钟内读写上百MB数据文件。 当你准备使用并行处理技术来实现批处理作业时,Spring Batch提供一系列选择,本章将对他们进行讲述,虽然某些功能不在本章中涵盖。从高层

  • 4.1扩展断点处理 在前面的章节中我们讲解了用事件处理函数处理调试事件的方法。用 PyDbg 可以很容 易的扩展这种功能,只需要构建一个用户模式的回调函数。当收到一个调试事件的时候,回 调函数执行我们定义的操作。比如读取特定地址的数据,设置更更多的断点,操作内存。操 作完成后,再将权限交还给调试器,恢复被调试的进程。 PyDbg 设置函数的断点原型如下: bp_set(address, descr

  • 我正在开发一个Quarkus扩展,它提供了一个拦截器(及其注释),以围绕此扩展提供的业务方法添加一些重试逻辑。这里没有什么新内容,当我在使用此扩展的应用程序中注释bean的公共方法时,这是有效的。 但是该扩展还提供了一些也带注释的@ApplationScoped bean,但拦截器没有拦截其中任何一个。 似乎拦截器不会检查/应用扩展本身。 我想知道这是有意的行为,还是我的扩展设置中的问题,如果是,

  • Spring Batch也为Step的分区执行和远程执行提供了一个SPI(服务提供者接口)。在这种情况下,远端的执行程序只是一些简单的Step实例,配置和使用方式都和本机处理一样容易。下面是一幅实际的模型示意图: 在左侧执行的作业(Job)是串行的Steps,而中间的那一个Step被标记为 Master。图中的 Slave 都是一个Step的相同实例,对于作业来说,这些Slave的执行结果实际上等