当前位置: 首页 > 知识库问答 >
问题:

如何表示Java未来结果的失败

戚弘和
2023-03-14

AFAIK将Callable/Runnable提交到ExecutorService是我想并行执行资源密集型代码的方法。因此,我的方法结构:

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 {
    ...
}

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

在提交任务之前,可能会出现一些问题,例如参数无效,一些可能失败的快速预处理代码。

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

  1. 如果提供给getResult的无效params立即返回null。在这种情况下,我必须检查getResult每次调用时是否返回null。
  2. 抛出检查过的异常而不是上面的。
  3. 实例化一个<代码>未来

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

  1. 我认为在我的情况下更好的选择是返回null,因为任务的结果是一个对象。
  2. 此外,我可以抛出检查过的异常并在ThreadPoolExecutor.afterExecute中处理它们(如NiranjanBhat所建议的)。请参阅处理来自JavaExecutorService任务的异常

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

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

共有2个答案

柴兴贤
2023-03-14

您可以使用 afterExecute 方法。这是在 ThreadPoolExecutor 中定义的,您需要覆盖它。
此方法在每个任务的执行完成后调用。您将在此回调方法中获取任务实例。您可以在任务中的某个变量中记录错误,并在此方法中访问它。

汤乐家
2023-03-14

我建议,对于任务处理过程中的失败,您只需抛出一个适当的异常。不要在executor中为此添加任何特殊处理。将会发生的是,它将被捕获,并存储在< code >未来中。当调用< code>Future的< code>get方法时,它将引发< code>ExecutionException,然后< code>get的调用方可以对其进行解包和处理。这基本上就是普通异常处理被转换成< code >可调用/未来范例的方式。这看起来像这样:

    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
    }

假设< code>get的调用方必须处理< code > execution exception s,那么您可以利用这一点来处理提交期间的失败。为此,您可以构造一个类似于Apache Commons的< code>constantFuture的< code>Future,但是它抛出一个给定的异常,而不是返回一个给定值。我不认为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; }
}

这有点危险-您在同步调用方法期间出现故障,并使其看起来像在异步调用方法期间发生故障。您正在将处理错误的负担从实际导致错误的代码转移到稍后运行的代码。不过,这确实意味着您可以将所有故障处理代码放在一个地方;这可能是一个足够的优势,让这一切变得值得。

 类似资料:
  • 我有2个期货(数据库表上的2个操作),我希望在保存修改之前检查两个期货是否都成功完成。 现在,我开始第二个未来在第一个(作为依赖),但我知道这不是最好的选择。我知道我可以使用来并行执行两个期货,但即使一个失败,另一个也会被执行(尚未测试) 在这种情况下,如果第一个未来成功执行,则第二个未来可能会失败。我想恢复第一个未来的更新。我听说过SQL事务,似乎是这样的东西,但是如何呢? 在我的情况下,理解要

  • 这是我的JavaFX控制器 所以我的问题是,在javaFX上下文中,处理<code>未来</code>结果的习惯用法是什么? 我知道我可以做,线程将阻塞,直到操作完成,但我会阻塞Application线程。我正在考虑在完成时进行回调,我发现了,哪种类型通过thenAccep执行此操作,但基于此答案,线程仍将被阻塞,这违反了Future的要点,就像答案中提到的那样。 在我的例子中,可调用的结果(在我

  • 我正在寻找一种将任意长度的期货列表转换为期货列表的方法。我使用的是Playframework,所以最终,我真正想要的是一个<code>未来〔结果〕,但为了让事情更简单,让我们说<code>将来〔List[Int]]通常的方法是使用<code>Future.sequence(…) 例如,执行以下操作不起作用: 我希望能够将1和3从那里拉出来,而不是只得到异常。我尝试将来使用<code>。折叠,但这显

  • 我正在为以下问题而苦苦挣扎:我有一个返回Future[Result]的方法,其中Result是我想用specs2中的数据表行检查的东西。 据我所知,以下代码每次都会阻塞并等待结果可用。 通常,我想异步进行所有调用,然后使用Future.sequence将Seq[Future[Result]]转换为Future[Seq[Result]],然后运行测试。 有什么合理的方法可以做到这一点吗?

  • 我有一个应用程序,通过点击按钮(该数字被定义)用户创建任务(可调用)做一些计算。我希望任务完成时能够做出反应。使用Future.get()阻止应用程序。有什么方法可以在Callable返回结果时做出反应吗?

  • 所以这个程序要做的是从键盘上获取输入的id、工时和工资。然后,它将计算加班工资、定期工资和总工资。计算完后,必须将应计算的身份证、小时数、工资、加班工资、定期工资和总工资打印到输出中。 而且,雇员的属性和行为应该在雇员类中。