从 Java ExecutorService 捕获并抛出自定义异常

Catch and throw custom Exception from Java ExecutorService

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

Other Stack Overflow posts seem to suggest collect into a List of Futures and use get() to catch the exceptions. 因此,这是我目前所拥有的:

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() vs. submit(),但后来我无法处理 JsonProcessingException。我看到另一个 post 建议创建一个 ThreadPoolExecutor 子类并覆盖 afterExecute(),但我无法处理 JsonProcessingException。

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

根据 the docs of ExecutionException (and also the docs of Future#get),它已经包装了该信息。也就是说,您可以使用它的 getCause 来检查 Callable 的 body.

抛出的 Exception

注意 Callable#call 本身会抛出一个 Exception... 当你从 Callable 抛出一个 Exception 时,它会被包装成一个 ExecutionException ] 将从 Future#get 方法中抛出, 对于每个 Callable,这意味着您可以更改循环以捕获 ExecutionException 对于每个 Future 并检查其 getCause!

所以您实际上不需要将其包装成自定义 ControllerException

您创建的 Callable 仍然可以 return null 类型 Void 例如,无需对其进行任何操作。

除非情况发生变化,否则在这种情况下不需要扩展ThreadPoolExecutor。您甚至不必强制转换为 ThreadPoolExecutor,因为 ExecutorService 接口已经具有您需要的 submit。当 Callable 出现问题时,只需从 Callable 中抛出任何你需要的 Exception (例如你提到的 JsonProcessingException ),然后检查 ExecutionException从每个 Future#get 方法判断是否抛出 JsonProcessingException(如果需要,您还可以在 中确定抛出哪个 )。

Is there a more elegant way than iterating through List and calling get on each to catch ExecutorException?

在我看来,不,没有,因为你想先提交所有Callable,然后让他们运行并行,最后检查他们的ExecutionException 对于 Callables' body 抛出的任何 Exception 对于每个 Callable(通过 returned FutureFuture#get通过 submit).