因此,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
方法指定为关闭钩子,用于清理执行程序服务的任务。
答案 0 :(得分:1)
在提出的解决方案中,应在shutdownNow()方法调用后调用wait。
未使用的ExecutorService应该被关闭以允许回收 它的资源。
shutdownNow():-
Future.cancel(假):-
简短说明和推荐:-
实际上,拥有一个List
对象本身不是线程安全的
单粒豆是无状态的。它不应该保持状态 在课堂上即使您将其声明为原型bean,它也是 维护列表(列表不是线程安全的)的一种好习惯 期货。
在内部,执行程序服务实现类(例如ThreadPoolExecutor,ScheduledThreadPoolExecutor等)负责处理所有线程安全问题。它使用BlockingQueue
来解决线程安全问题。而且,它会相应地处理异常和不同状态。您可能需要了解所有内部原理(即幕后发生的事情),才能提出一个好的自定义解决方案。
最简单,最好的方法是使用executor服务实现中可用的标准实现(ThreadPoolExecutor,ScheduledThreadPoolExecutor等),以避免产生任何不利影响(例如,内存泄漏,线程安全问题)。
>