关闭执行程序服务(等待终止时)与等待取消已提交任务(使用提交的期货)之间的比较

问题描述 投票:0回答:1

因此,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注释中推断出它是一个用于清理执行程序服务任务的关闭钩子。

java spring executorservice
1个回答
1
投票

在建议的解决方案中,应在shutdownNow()方法调用之后调用wait。

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

shutdownNow时(): -

  • 将运行状态转换为停止
  • 如果启动则中断工作人员
  • 排空队列 - 删除所有线程

Future.cancel(false): -

  • 不会中断正在运行的任务
  • 如果任务已完成,已取消或由于某些其他原因无法取消,则取消尝试将失败。您可能需要具有其他逻辑来处理不同的方案。 shutdownNow()已经处理了这些场景。

简短说明和建议: -

  • 实际上,拥有List对象本身并不是线程安全的
  • 单身豆是无国籍的。它不应该维持班级的状态。即使您将其声明为原型bean,维护期货的List(List不是线程安全的)也不是一个好习惯。

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

最简单和最好的方法是使用执行程序服务实现中可用的标准实现(ThreadPoolExecutor,ScheduledThreadPoolExecutor等)来避免任何不利影响(即内存泄漏,线程安全问题)。

© www.soinside.com 2019 - 2024. All rights reserved.