如果发生异常,如何停止执行程序服务中的可调用任务

How to stop Callable tasks in Executor service if exception occur

我正在尝试实现示例应用程序来测试 Callable 和 ExecutorService 接口。

在我的应用程序中我有:

@Bean("fixedThreadPool")
public ExecutorService fixedThreadPool() {
    return Executors.newFixedThreadPool(5);
}

然后:

public void removeUserIds(Set<String> userIds) {
 UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://localhost:8080/remove");
    final List<Callable<String>> callables = new ArrayList<>();  
    userIds.forEach(userId -> {
        final Callable<String> task = () -> callServiceToRemove(builder,userId); //Call to remote service using RestTemplate
        callables.add(task);
    });

    try {
        final List<Future<String>> futureList =
            executor.invokeAll(callables);

        futureList.forEach(future -> {
            try {
                log.info(future.get());
            } catch (final Exception e) {
                log.error("Error : "+ e.getMessage());
            } 
        });
    } catch (final Exception e) {
        log.error("Error Error Error : "+ e.getMessage());
    } finally {
        executor.shutdown();
    }
}

当我使用 100 个 userIds 调用 removeUserIds() 方法时,它在快乐流程中工作正常,但如果服务不可用或关闭,第 100 次打印错误。如果服务不可用或关闭,我无法 stop/terminate 线程,因此服务不会发生进一步的调用。 任何人都可以在这里帮助解决这个问题,如果服务中断,我如何停止线程执行,或者在这里提出可行的解决方案?

将 callServiceToRemove 调用移到 try catch 块中。

在 catch 块中你可以使用 executor.shutdownNow();

shutdownNow() 尝试停止所有正在执行的任务,停止等待任务的处理,以及 returns 等待执行的任务列表。 此方法不会等待主动执行的任务终止并尝试强制停止它们。除了尽最大努力停止处理正在执行的任务之外,没有任何保证。此实现通过 Thread.interrupt() 取消任务,因此任何未能响应中断的任务可能永远不会终止。

与其说是编码问题,不如说这是设计问题。可能有几种方法。您可以以此为例:

使用全局标志

在实际触发远程服务调用之前寻找全局布尔标志,例如 Globals.serviceUnavailable这个全局标志可以由遇到远程错误的第一个服务设置。这里是对代码的更改。

final Callable<String> task = () -> {
   try{    
       if( !Globals.serviceUnavailable ) callServiceToRemove(builder,userId);
   }
   catch( ServiceUnavailableException e ){ //Or whatever your exception is
       Globals.serviceUnavailable = true; //Notify the remaining tasks that the service is unavailable.
   }

}

当然,你得看看更新Globals.serviceUnavailable的值是否需要同步。 (如果您可以部分成功删除该批用户 ID,则可能没有必要。)

此外,只有当您的线程池远小于提交的任务数时,这才有效,我在这里看到的就是这种情况。