首页 > 解决方案 > 从 Java ExecutorService 捕获并抛出自定义异常

问题描述

我有一个函数可以遍历 HappyObjects 列表并异步设置它们的字段。在 Callable 中,可能会发生 JsonProcessingException。我必须将这个函数中的这个异常和其他异常包装到一个自定义异常(ControllerException)中,然后抛出它。

其他 Stack Overflow 帖子似乎建议收集到期货列表中并使用 get() 来捕获异常。因此,这就是我到目前为止所拥有的:

default List<HappyObj> fillfunction(final List<HappyObj> happyObjs) throws ControllerException {
    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
    List<Future<HappyObj>> futures = new ArrayList<>();

    for (HappyObj happyObj : happyObjs) {
      Future<HappyObj> future = executor.submit(
          () -> {
            final List<Mood> moods = getMoods();

            for (Mood mood : moods) {
              final String json = getJsonEmotion();

              ObjectMapper mapper = new ObjectMapper();
              mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

              List<Emotion> emotions =
                  mapper.readValue(json, new TypeReference<List<Emotion>>() {}); //JsonProcessingException can occur here

              MoodMetadata metadata = mood.getMoodMetadata();
              if (metadata != null && metadata.getEmotionMetadata() != null) {
                metadata.getEmotionMetadata().setEmotions(emotions);
              }
            }
            happyObj.setMoods(moods);
            return happyObj;
          });
      futures.add(future);
    }
    executor.shutdown();
    final long maxSlaSec = 1;
    try {
      executor.awaitTermination(maxSlaSec, TimeUnit.SECONDS);
      List<HappyObj> happyResult = new ArrayList<>();
      for (Future<HappyObj> future : futures) {
        happyResult.add(future.get());
      }
      return happyResult;
    } catch (InterruptedException | ExecutionException e) {
      executor.shutdownNow();
      throw new ControllerException(e);
    }
  }

有没有比遍历List<Future>并调用 get 来捕获 ExecutorException 更优雅的方法?我考虑过使用execute() 与 submit(),但后来我无法处理 JsonProcessingException。我看到另一个帖子建议创建一个 ThreadPoolExecutor 子类并覆盖 afterExecute(),但我无法处理 JsonProcessingException。

我问这个问题的原因之一是因为这个方法主要由 setter 组成,所以该函数最初是在操作给定的对象并返回 void。

标签: javamultithreadingexceptionthreadpoolexecutor

解决方案


根据(以及的文档ExecutionException的文档,它已经包装了该信息。也就是说,您可以使用它来检查's body抛出的内容。Future#getgetCauseExceptionCallable

请注意,Callable#call它本身会抛出一个Exception... 当您从 中抛出 anExceptionCallable,它将被包装到一个ExecutionException将从Future#get方法中抛出的for eachCallable中,这意味着您可以更改循环以捕获一个ExecutionException for eachFuture并检查它getCause

因此,您实际上不需要将其包装到 custom ControllerException

Callable例如,您创建的s 仍然可以返回null类型Void,而无需对它们做任何事情。

除非场景发生变化,否则在这种情况下您不需要扩展ThreadPoolExecutor。您甚至不必强制转换为ThreadPoolExecutor,因为ExecutorService接口已经具有submit您需要的 s 。Exception当 中出现问题时,只需从Callable(例如JsonProcessingException您提到的)中抛出您需要的任何东西,然后检查每个Callable方法ExecutionExceptionFuture#get的)。JsonProcessingException

有没有比遍历 List 并在每个上调用 get 来捕获 ExecutorException 更优雅的方法?

在我看来,不,没有,因为你想先提交所有Callables,然后让它们并行运行,最后检查它们ExecutionException是否有任何由s 的主体Exception抛出的(通过返回的 by )。CallableCallableFuture#getFuturesubmit


推荐阅读