在 spring 启动 Rest API 中关闭 ExecutorService

shutting down ExecutorService in a spring boot Rest API

正在构建部署在 weblogic 12c 上的 spring boot rest api 应用程序。 我的要求之一是 运行 对每个传入请求执行一些较长的 运行ning 任务。 传入的休息请求可能会导致多个异步任务执行。

因为我不关心响应,也不关心这些任务会导致的任何异常,所以我选择使用 ExecutorService 而不是 Callable 或 CompletableFuture。

ExecutorService executorService =
  Executors.newFixedThreadPool(2, new CustomizableThreadFactory("-abc-"));

然后对于我在控制器中收到的传入请求 运行 两个 for 循环并将这些任务分配给 ExecutorService:

for (final String orderId : orderIds) {
        for (final String itemId : itemIds) {               
            exec.execute(new Runnable() {
                public void run() { 
                    try {           
                         //call database operation
                    }catch(Throwable t) {
                       logger.error("EXCEPTION with {} , {}" ,orderId,itemId 
                    )
                }   
            });
        }//for          
    }//for

我的问题是关于关闭 ExecutorService。 我知道正常关机 ( shutdown ) 混合关机 ( awaitTermination ) 或突然关机 ( shutdownNow )

对于休息 api 应用程序,三者之间的首选方法是什么?

对于可以创建多少个线程池也有任何限制,因为创建的 ExecutorService 线程池的数量将由传入请求的数量驱动

我们目前有类似的需求,这是一个很难解决的问题,如果你愿意的话,你想使用合适的锤子。编排长 运行 进程有非常重量级的解决方案,例如 SpringBatch。

首先,不要费心停止和启动 ExecutorService。 class 的全部意义在于减轻线程管理的负担,因此您无需自己创建和停止线程。所以你不需要管理经理。

但是要小心你的方法。无需使用队列或其他负载平衡技术来巧妙地平衡应用程序中多个实例的长 运行 进程。或者管理线程终止时发生的事情,您可能会遇到麻烦。总的来说,我会说现在直接与线程或线程池交互并使用更高级别的解决方案来解决此类问题没有多大意义。

awaitTermination 通常更安全一些,而 shutdownNow 更强大。如果您希望执行程序尽快关闭,但只有在它完成创建它要做的所有事情之后,才可以在功能方法甚至可运行程序中使用 awaitTermination 通常是个好主意.换句话说,当没有执行者正在执行的活动任务时。 例如)

ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors);
Observable.of(items).schedule(Schedulers.from(executor)).flatMap(item -> {
   ... // this block represents a task that the executor will execute in a worker thread
}).onSubscribe(onNext -> 
   logItem(onNext), throwable -> 
   throwable.printStackTrace(), /* onComplete */ () -> 
   executor.awaitTermination(60, TimeUnit.Seconds)
);
... // you need to shutdown asap because these other methods below are also doing some computation/io-intensive stuff

现在,当此方法完成时,它将调用 awaitTermination,如果它没有执行任何任务,它将立即关闭池,如果任务仍在执行,则最多等待 60 秒。

在大多数情况下,线程或工作线程将停止活动 60 秒不活动,因为这通常是默认设置。

另一方面,如果您希望任务在(举一些例子)抛出异常、出现安全漏洞或另一个 module/service 失败时立即停止执行,您可能想要使用 shutdownNow() 立即停止所有任务而无需等待。

我建议在两者之间进行选择,如果您不希望任务在发生异常时继续执行 - 即不再有原因,则在 catch 块中使用 shutdownNow到 return 给客户端的项目列表,因为其中一个项目没有被添加到列表中。 否则,我建议在将 try-catch 设置为一分钟后使用 awaitTermination,以便在线程池执行完您指定的所有任务后立即安全地关闭线程池。但只有当您知道执行者不会负责执行更多任务时才这样做。

简单的shutdown,如果这是你的选择,也是一个很好的方法。根据 Oracle 文档,shutdown 将拒绝所有传入任务,但会等待当前任务执行完毕。

如果您不确定何时需要关闭执行程序,使用 @PreDestroy 方法可能是个好主意,这样执行程序就会在您的 bean 上调用 destroy 方法之前:

@PreDestroy
private void cleanup(){
   executor.shutdown();
}