FutureTask get vs 运行,任务永远不会完成

FutureTask get vs run, task never finishes

我正在学习 Callables 并决定制作一个非常简单的程序。问题是当我调用 getFutureTask() 时线程被阻塞了; Thread.State:TIMED_WAITING(在对象监视器上)

你能告诉我为什么会这样吗?为什么当我在 futureTask.get() 之前写 futureTask.run() 时我的程序可以运行; 我确实理解 get() 方法等待和 returns 结果。但无法理解 运行() 的作用。 非常感谢您的回答!

   public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
       FutureTask futureTask = getFutureTask(1);
        System.out.println(futureTask.get());

    }


  public static FutureTask<Integer> getFutureTask(Integer i) {
        return new FutureTask<Integer>(() -> i*45);

    }

来自FutureTask的API:

get() - Waits if necessary for the computation to complete, and then retrieves its result.

run() - Sets this Future to the result of its computation unless it has been cancelled.

因此,run() 实际上会 运行 你的 FutureTask 并最终得出一个计算结果。另一方面,如果计算完成,get() 会给你结果。 但是它不会开始计算并且不会调用run()本身。

另见@Zabuzard 的评论:

run is the method that actually starts execution of the task. It is supposed to be called in a different thread, for example by an ExecutorService. get will not trigger execution, it just waits until the task is done, which happens at the end of run(). FutureTask is not really supposed to be used directly by an user. Instead you should look into ExecutorService and CompletableFuture for a nice interface to spawn async tasks.

您的函数 () -> i*45 只是一个可调用函数。除非您真正开始执行,否则它不会真正执行。 而这正是 run() 的用途。

因此,除非您不显式启动您的线程,否则不会调用任何 FutureTask。 而 get() 被设计为等待一个线程完成。 所以,通常情况下,你开始一项任务(使用 run()),做一些其他的事情,然后使用 get() 得到结果,或者如果任务花费的时间比预期的多,就在那里等待。

你可以检查一下,例如通过 运行 一些 System.out:

 public static FutureTask<Integer> getFutureTask(Integer i) {
    return new FutureTask<Integer>(() -> {
        System.out.println("Task started");
        return i * 45;
    });
}

你什么都看不到

run vs get

run是实际开始执行任务的方法。它应该在 不同的线程 中调用,例如 ExecutorService.

get 不会触发执行 ,它只是等待直到任务完成,即直到 run 完成。这显然意味着您在另一个线程之前或从另一个线程以某种方式调用 run


ExecutorService and CompletableFuture

FutureTask 不应该被用户直接使用。它更多是在幕后使用的 class 类型,以实现漂亮的异步 API。更具体地说,它是 Future 的基本实现,例如当您使用它生成任务时由 ExecutorService 返回。

您应该查看 ExecutorService

ExecutorService service = Executors.newCachedThreadPool();
...
Future<Integer> task = service.submit(() -> i * 45);
...
Integer result = task.get();

CompletableFuture

CompletableFuture<Integer> task = CompletableFuture.supplyAsync​(() -> i * 45);
...
Integer result = task.get();

用于生成异步任务的易于使用的界面。

CompletableFutures 的优点是您还可以设置一个操作管道,一旦前一个操作完成,这些操作将全部异步执行。例如:

CompletableFuture<Void> task = CompletableFuture.supplyAsync(Foo::readSomeFile)
    .thenApplyAsync(Foo::validateData)
    .thenApplyAsync(Foo::compressData)
    .thenAcceptAsync(Foo::uploadData);