在关闭执行程序服务(等待终止)和等待取消已提交任务(使用提交者的未来)之间的比较

时间:2018-09-04 10:10:06

标签: java spring executorservice

因此,Oracle itself建议的关闭ExecutorService的最佳做法如下:

@PreDestroy
public void cleanUp(){
        executorService.shutdown();

        try {
            if (executorService.awaitTermination(TIMEOUT, TimeUnit.MILLISECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
        }
}

这也将取消所有待处理的任务。我想知道何时上面的代码段比以下代码更受欢迎:

private List<Future> tasks = Collections.EMPTY_LIST;

public void doStuff(){
    for (Service service : services) {
            Future<?> future = executorService.submit(()->service.update(args));
            tasks.add(task);
    }
}

@PreDestroy
public void cleanUp() {

    for (Future task : tasks) {
        task.cancel(false);
    }
}

后者将允许正在运行的任务完成而不会中断它们(tasks.cancel(false))。在这种方法中,没有超时,因此任务中的无限循环将阻止应用程序停止。此外,我们还有一个仍在运行的执行程序服务:但是,如果可以确定在完成已取消的任务之后再没有其他任务可以提交,那么我们是否应该真正关心这一点?

在人们想要等待作业任务的终止/完成然后继续进行实际关闭之前,我对什么是最佳实践最感兴趣。为什么我们实际上要关心执行程序服务本身的关闭?

Imho拥有一个可以在应用程序关闭时取消的期货清单,这是一种更为简洁的解决方案,因为可以选择哪些将被中断并等待完成。

对此,我们欢迎提供更多详尽的见解。

这些都是Spring bean的一部分,您可以从@PotsDestroy注释中推断出来,该注释用于将cleanUp方法指定为关闭钩子,用于清理执行程序服务的任务。

1 个答案:

答案 0 :(得分:1)

在提出的解决方案中,应在shutdownNow()方法调用后调用wait。

  

未使用的ExecutorService应该被关闭以允许回收   它的资源。

shutdownNow():-

  • 将运行状态转换为“停止”
  • 启动后中断工作程序
  • 排空队列-删除所有线程

Future.cancel(假):-

  • 不中断正在运行的任务
  • 如果任务已经完成,具有 已被取消,或因其他原因无法取消 原因。您可能需要其他逻辑来处理不同的问题 场景。 shutdownNow()已经可以处理这些情况。

简短说明和推荐:-

  • 实际上,拥有一个List对象本身不是线程安全的

  • 单粒豆是无状态的。它不应该保持状态 在课堂上即使您将其声明为原型bean,它也是 维护列表(列表不是线程安全的)的一种好习惯 期货。

在内部,执行程序服务实现类(例如ThreadPoolExecutor,ScheduledThreadPoolExecutor等)负责处理所有线程安全问题。它使用BlockingQueue来解决线程安全问题。而且,它会相应地处理异常和不同状态。您可能需要了解所有内部原理(即幕后发生的事情),才能提出一个好的自定义解决方案。

最简单,最好的方法是使用executor服务实现中可用的标准实现(ThreadPoolExecutor,ScheduledThreadPoolExecutor等),以避免产生任何不利影响(例如,内存泄漏,线程安全问题)。

>