在Spring Boot Rest API中关闭ExecutorService

时间:2019-06-21 02:19:44

标签: java spring multithreading weblogic executorservice

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

由于我既不在乎响应,也不在乎这些任务会导致的任何异常,因此我选择使用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线程池的数量将由传入请求的数量来驱动

2 个答案:

答案 0 :(得分:2)

我们目前有类似的要求,这是一个很难解决的问题,因为您想使用正确的锤子。有非常重的解决方案来协调长时间运行的流程,例如SpringBatch。

首先,尽管不要打扰停止并启动ExecutorService。该类的全部要点是减轻了线程管理的负担,因此您无需自己创建和停止Threads。因此,您无需管理经理。

但是请谨慎使用。无需使用队列或其他负载平衡技术来智能平衡应用程序中各个实例之间长时间运行的进程。或管理线程死后发生的事情,您可能会陷入麻烦。总的来说,如今我要说的是,直接与Threads或ThreadPools进行交互并针对此类问题使用更高级别的解决方案没有多大意义。

答案 1 :(得分:1)

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秒钟不活动的状态下停止活动,因为这通常是默认设置。

另一方面,如果您希望任务在引发异常(举一些例子),安全性受到破坏或其他模块/服务失败后立即停止执行,则可能要使用shutdownNow ()立即停止所有任务,而无需选择等待。

我建议在两者之间进行选择的建议是,如果您不希望在出现异常的情况下继续执行任务,即不再有返回的理由,请在catch块中使用shutdownNow给定客户的项目列表,因为其中一个项目未添加到列表中。 否则,建议您将try-catch设置为一分钟后再使用awaitTermination,以在线程池执行完您赋予的所有任务后立即安全关闭线程池。但是只有当您知道执行者将不负责执行所有其他任务时,才这样做。

简单的shutdown(如果您可以选择)也是一种好方法。根据Oracle文档,shutdown将拒绝所有传入的任务,但要等到当前任务完成执行。

如果不确定何时需要关闭执行器,最好使用@PreDestroy方法,以便执行器将在您的bean上调用destroy方法之前:

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