【问题标题】:How to know if a Future is created with Callable or Runnable如何知道 Future 是用 Callable 还是 Runnable 创建的
【发布时间】:2019-07-15 15:25:36
【问题描述】:

我正在涉足期货。可以使用 Runnable 和 Callable 创建 Future。有没有办法决定它是如何创建的?

例如,我有以下代码:

        Future<?>       future  = null;
        Future<?>       future2 = null;
        ExecutorService service = null;
        service = Executors.newSingleThreadExecutor();
        future = service.submit(() -> {
                for (int i = 0; i < 5; ++i) {
                    System.out.println("Printing record: " + i);
                    Thread.sleep(5);
                }
                return "Done";
            });
        future2 = service.submit(() -> System.out.println("Printing zoo inventory"));
            System.out.println("================================================================");
        System.out.println(future);
        System.out.println(future.get().getClass());
        System.out.println(future.get());
        System.out.println("================================================================");
        System.out.println(future2);
        try {
            System.out.println(future2.get().getClass());
            System.out.println(future2.get());
        } catch (ExecutionException e) {
            System.out.println("Could not do a get");
        }
        System.out.println("================================================================");

这导致以:

结尾
================================================================
java.util.concurrent.FutureTask@5caf905d[Completed normally]
class java.lang.String
Done
================================================================
java.util.concurrent.FutureTask@1f32e575[Completed normally]
Exception in thread "main" java.lang.NullPointerException
        at ZooInfo.main(ZooInfo.java:56)

我可以通过以下方式解决这个问题:

                    if (future2.get() == null) {
                        System.out.println("Made with a Runnable");
                    } else {
                        System.out.println(future2.get().getClass());
                        System.out.println(future2.get());
                    }

这样做的问题是,当 Runnable 仍然需要一些时间时,我正在等待获取。有没有办法在不使用 get() 的情况下确定 Future 是使用 Runnable 还是 Callable 创建的?

【问题讨论】:

  • “问题在于”Callable 也可以返回 null。
  • 为什么? Runnable 和 Callable 的行为方式相同。 getClass() on nullget 返回但是是个坏主意。
  • 这个问题有实际用途吗?通常,当您编写一个依赖于期货的系统时,您知道您发送了什么并且您get 或不get 相应地。你不会随意将你不知道的任务倒入你的执行器服务中。
  • 即使使用get,它们也无法区分,因为您也可以在Callable 中返回null
  • 在组织中,您计划您的 API。您不只是从未知来源获得随机任务。你编写的模块必须有一定的意义,定义的输入和定义的输出,特别是当你使用像 Java 这样的严格类型的语言时。您的 Future 不会有 ? 作为其类型。无论如何,您的情况归结为在对结果使用任何方法之前必须进行空检查 - 因为当您得到未知结果时,其中一些可能为空。

标签: java runnable callable


【解决方案1】:

我不相信您真的需要知道Future 是从Runnable 还是Callable 创建的。

一方面,创建Future 的方法比这更多:例如,CompleteableFuture 不是从其中任何一个创建的;而且,更一般地说,由于Future 是一个接口,因此可以随心所欲地创建实例。

另外:Future 的抽象是它在完成或抛出异常时为您提供(可能为 null)值。这就是它的全部目的。

(此外,您当前检查返回值是否为 null 的方法无法可靠地工作,因为允许 Callable.call() 返回 null)。

如果您需要它来做其他事情,您可能需要重新审视您的设计,以便您可以简单地按照预期处理它。


但是,如果您确实有一个用例需要您知道它是如何创建的,那么您需要控制创建。与其让调用者直接向执行者提交代码,不如封装在一个类中,如下所示:

class YourExecutor {
  // Initialize in ctor.
  private final ExecutorService executor;

  FromRunnable submit(Runnable r) {
    return new FromRunnable(executor.submit(r));
  }

  <T> FromCallable<T> submit(Callable<? extends T> c) {
  return new FromCallable<>(executor.submit(c));
  }
}

其中FromRunnableFromCallable&lt;T&gt; 分别是实现Future&lt;Void&gt;Future&lt;T&gt; 的类,它们将所有方法委托给兼容Future 的另一个实例(作为构造函数参数传递)。

然后您可以使用instanceof 检查出处;或通过其他方式,例如扩展一个通用的基本案例或接口,提供一种描述出处的方法。

但是,重申一下,更好的方法是设计您的代码,使其不需要知道。

【讨论】:

  • 嗯,我只是在学习这些东西,所以我可能会问一些对于 Futures 经验丰富的人来说似乎很奇怪的问题。 :-D 我同意一个好的设计应该规避这样的事情。但我经常看到,一时冲动比长期更重要。也可能是首先它不被认为是重要的,后来它是。新的见解和类似的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多