Java 关闭spring引导Rest API中的ExecutorService

Java 关闭spring引导Rest API中的ExecutorService,java,spring,multithreading,weblogic,executorservice,Java,Spring,Multithreading,Weblogic,Executorservice,我正在构建部署在weblogic 12c上的spring boot rest api应用程序。 我的要求之一是对每个传入的请求运行一些长时间运行的任务。 传入的rest请求可能导致多个异步任务执行 因为我不关心响应,也不关心这些任务会导致的任何异常,所以我选择使用ExecutorService,而不是Callable或CompletableFuture ExecutorService executorService = Executors.newFixedThreadPool(2, new

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

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

ExecutorService executorService =
  Executors.newFixedThreadPool(2, new CustomizableThreadFactory("-abc-"));
然后,对于我在controller中收到的传入请求,运行两个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
我的问题是关于关闭Executor服务。 我知道正常关机(关机)、混合关机(等待终止)或突然关机(立即关机)

对于RESTAPI应用程序,三者之间的首选方法是什么


另外,由于创建的ExecutorService线程池的数量将由传入请求的数量决定,因此可以创建的线程池的数量是否有任何限制?我们目前有类似的要求,这是一个很难解决的问题,因为如果愿意,您希望使用正确的锤子。有一些非常重要的解决方案可以协调长时间运行的流程,例如SpringBatch

首先,不要费心停止和启动Executor服务。该类的全部目的是减轻线程管理的负担,因此您不需要自己创建和停止线程。所以你不需要管理经理


但是要小心你的方法。无需使用队列或其他负载平衡技术,即可在应用程序中的实例之间智能地平衡长时间运行的流程。或者管理线程死亡时发生的事情,您可能会陷入一个麻烦的世界。一般来说,我想说的是,现在直接与线程或线程池交互,并使用更高级别的解决方案来解决这类问题没有多大意义。

终止
通常更安全一些,而
关闭现在
更有力。如果您希望执行器尽快关闭,但只有在它完成了创建它要做的所有事情之后,才可以在函数方法中使用
waittermination
,甚至在runnable中使用它。换句话说,当执行者没有正在执行的活动任务时。 例)

现在,当这个方法完成时,它将调用
waittermination
,如果它没有执行任何任务,它将立即关闭池,如果任务仍在执行,它将等待60秒

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

另一方面,如果您希望在(举一些例子)引发异常、安全性出现漏洞或另一个模块/服务失败后立即停止执行任务,则可能需要使用shutdownNow()立即停止所有任务,而不必等待

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

简单的
关闭
,如果这是您的选择,也是一个好方法<根据Oracle文档,代码>关机将拒绝所有传入任务,但等待当前任务完成执行

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

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

不过,我在很大程度上同意@Snickers3192。管理自己的线程池肯定会给您带来很多麻烦。由于这个原因,通常不建议这样做,特别是如果您计划在整个应用程序的多个位置创建多个。虽然,,在某些情况下,它们可能是必要的,也可能是重要的性能提升因素。谢谢,我将回答Snickers3192,并提出一些问题/疑问-但感谢您的回答-给我一个进度当您说不要麻烦启动/停止ExecutorService时-因为我将ExecutorService创建为本地服务变量-您是否暗示在方法(和所有线程)完成后,ExecutorService将得到gced,所以我不必麻烦了?(通过将ExecutorService实例化为局部变量,我不知何故觉得我没有正确地编写代码)。关于一根线什么时候会死——根据我在这里的理解,我正在试着抓住它。也许我错过了你的要点,我也只是想从控制器那里知道,如果我只是用@Aync注释调用我的服务-这是一个选项吗……你可以在一个单例bean中使用执行服务,它应该将你的实际进程与你的执行服务解耦
@Async
在您希望立即向客户机返回响应时是必需的,这仅在您的情况下才需要,如果您在流程完成之前一直处于阻塞状态。除非你想完全取消ExecutionService,只需使用一个
@Async
。谢谢,是的,我这个端点的唯一要求是一个接一个地启动并忘记多个任务(db操作),而不是等待所有任务的结果。根据你上面的评论,我一点也不愿意尝试拼凑起来
@PreDestroy
private void cleanup(){
   executor.shutdown();
}