【问题标题】:why does my threadExecutor calls the same callback twice?为什么我的 threadExecutor 两次调用相同的回调?
【发布时间】:2014-12-28 13:12:21
【问题描述】:

我有这个代码:

public <T> T executeCodeBlockWithTimeLimit(String criticalBlockTimeOutMilli, Callable<T> callable) throws
        Exception {
    ExecutorService service = Executors.newSingleThreadExecutor();
    Future<T> future = service.submit(callable);

    startStopWatch();
    T result;

    if (criticalBlockTimeOutMilli != null) {
        result = future.get(Long.parseLong(criticalBlockTimeOutMilli), TimeUnit.MILLISECONDS);
    } else {
        result = callable.call();
    }
    long timeElapsed = stopStopWatch();
    e2eResult.runTime = timeElapsed;
    service.shutdown();
    return result;
}

在外部方法中:

    Callable<Void> callable = new
            Callable<Void>() {
                @Override
                public Void call() throws
                        Exception {

                    System.out.println("22222");

                    return null;
                }
            };
    timerUtils.executeCodeBlockWithTimeLimit(criticalBlockTimeOutMilli, callable);

我看到控制台打印了

22222
22222

为什么要调用两次?

【问题讨论】:

  • criticalBlockTimeOutMilli 是否设置为空?

标签: java multithreading callable executor


【解决方案1】:

当您使用submit 方法从Executor 获得Future 时,此方法调用Callable 对象方法并存储结果。在您的代码中,您首先得到 Future 然后如果变量 criticalBlockTimeOutMilli<b>null</b> 您调用 Callable 对象上的 call() 方法。这意味着执行两次 Callable 对象。

您应该改用get() 方法,因为该方法使用的是从您的Future 对象中收集的结果(请参阅Future#get() method)。

【讨论】:

  • 但是Future.get 是懒惰的执行者。不?然后调用callable.call 永远不会触发第一次执行(来自submit 的那个)。没有?
  • but Future.get is lazy executor. No? 这不是 懒惰的执行者。实际上,当您将 Callable 对象提交给 Executor 时,这个对象会在 new Thread 中运行它并将结果存储在 Future 对象 (Executor#submit(Callable))。 Indead Lazy Executor 意味着 Callable 对象仅在调用 Future.get() 方法时运行。
  • then calling callable.call never triggers the first execution (the one from submit). No? 这是启动Callable.call() 方法(提交时)的Executor。你不需要自己启动它。如果你这样做,它会在 current/main Thread 中运行该方法。
【解决方案2】:
if (criticalBlockTimeOutMilli != null) {
    result = future.get(Long.parseLong(criticalBlockTimeOutMilli), TimeUnit.MILLISECONDS);
} else {
    result = future.get();
}

【讨论】:

    【解决方案3】:

    如果criticalBlockTimeOutMilli 为null,那么executor 将调用callable 一次,并且

    结果 = callable.call();

    将再次调用它。

    (?)

    【讨论】:

      【解决方案4】:

      您可能不清楚ExecutorService,这是参考的javadoc:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#submit(java.util.concurrent.Callable)

      当您调用submit(Callable) 时,执行器服务将为您调用您的可调用对象。你也不需要调用它。

      【讨论】:

        【解决方案5】:

        假设criticalBlockTimeOutMilli, 设置为null,你调用call 方法两次。一种通过执行器服务提交方法如下:

        Future<T> future = service.submit(callable);
        

        然后你通过如下调用方法调用它:

        result = callable.call();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-08-02
          • 2023-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多