java - 如何表示 Java Future 结果失败

标签 java future

AFAIK 提交 Callable/RunnableExecutorService如果我想并行执行资源密集型代码,这是可行的方法。因此我的方法结构:

public class ServiceClass {
    protected final ExecutorService executorService = Executors.newCachedThreadPool();

    public Future<Result> getResult(Object params) {
        if (params == null) {
            return null; // In situations like this the method should fail
        }
        // Do other fast pre-processing stuff
        return executorService.submit(new CallProcessResult(params));
    }

    private class CallProcessResult implements Callable<Result> {
        private Object params;
        public CallProcessResult(Object params) {
            this.params = params;
        }
        @Override
        public Result call() throws Exception {
            // Compute result for given params
            // Failure may happen here too!
            return result;
        }
    }
}
public class Result {
    ...
}

我在上面的代码中标记了 2 个可能发生故障的地方。对于这两种情况,可用于错误处理的选项完全不同。

提交任务前可能会出现参数无效、一些快速预处理代码可能会失败等问题。

我在这里看到了几种表示失败的方法:

  1. 如果无效params提供给 getResult立即返回 null。在这种情况下,我必须检查是否 getResult每次我调用它时都返回 null。
  2. 抛出已检查的异常而不是上述异常。
  3. 实例化一个Future<Result>get() 上返回 null要求。我会用 Apache Commons 做到这一点 ConcurrentUtils.constantFuture(null) .在这种情况下,我希望 getResult总是返回一些非空 Future<Result> .我更喜欢这个选项,因为它符合第二种情况。

在任务执行期间我可能会遇到严重的错误,例如内存不足、文件损坏、文件不可用等。

  1. 我想在我的情况下更好的选择是返回 null,因为任务的结果是一个对象。
  2. 此外,我可以抛出已检查的异常并在 ThreadPoolExecutor.afterExecute 中处理它们(正如 NiranjanBhat 所建议的那样)。参见 Handling exceptions from Java ExecutorService tasks

哪种做法更好(在两种情况下)?

也许有不同的方法或我应该使用的设计模式?

最佳答案

我建议对于任务处理期间的失败,您只需抛出一个适当的异常即可。不要在执行器中为此添加任何特殊处理。将会发生的是它会被捕获,并存储在 Future 中。当Futureget方法被调用时,会抛出一个ExecutionExceptionget的调用者可以然后拆包处理。这本质上是将正常的异常处理转换为 Callable/Future 范例的方式。这看起来像这样:

    Future<Result> futureResult = serviceClass.getResult("foo");

    try {
        Result result = futureResult.get();
        // do something with result
    }
    catch (ExecutionException ee) {
        Throwable e = ee.getCause();
        // do something with e
    }

鉴于 get 的调用者必须对 ExecutionException 进行这种处理,因此您可以利用它来处理提交期间的失败。为此,您可以构造一个类似于 Apache Commons 的 constantFutureFuture,但它会抛出给定的异常而不是返回给定的值。我不认为 JDK 中有类似的东西,但写起来很简单(如果乏味的话):

public class FailedFuture<T> implements Future<T> {
    private final Throwable exception;

    public FailedFuture(Throwable exception) {
        this.exception = exception;
    }

    @Override
    public T get() throws ExecutionException {
        throw new ExecutionException(exception);
    }

    @Override
    public T get(long timeout, TimeUnit unit) throws ExecutionException {
        return get();
    }

    @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; }
    @Override public boolean isCancelled() { return false; }
    @Override public boolean isDone() { return true; }
}

这有点狡猾 - 您在同步调用方法期间失败,并使其看起来像在异步调用方法期间失败。您正在将处理错误的负担从实际导致它的代码转移到稍后运行的代码。不过,这确实意味着您可以将所有故障处理代码放在一个地方;这可能足以让这一切变得有值(value)。

关于java - 如何表示 Java Future 结果失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13928818/

相关文章:

java - JSF ApplicationScoped HashMap - ConcurrentHashMap

来源不明的 java.util.NoSuchElementException

java - 如何等待 future 列表得到满意的结果?

基于第一个 future 结果的Scala future 返回

java - java/静态模拟中静态调用中创建的对象

java - 数组未显示正确的值

java - Spring Data JPA 如何使用@repository 传递变量

scala - 如何在 Akka Future 中包装 java.util.concurrent.Future?

concurrency - rust future -cpupool : inconsistent behavior explanations

scala - Scala 中压平 'reactive' 调用结果