user15204218
user15204218

Reputation:

FutureTask get vs run, task never finishes

I am learning Callables and decided to make a very simple program. The problem is that the Thread is blocked when I call getFutureTask(); Thread.State: TIMED_WAITING (on object monitor)

Could you please tell me why is it so and why does my program work when I write futureTask.run() before futureTask.get(); I do understand that get() method waits and returns result. but can't understand what method run() does. I do appreciate your answers a lot!

   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);

    }

Upvotes: 2

Views: 2534

Answers (3)

Indivon
Indivon

Reputation: 1874

Your function () -> i*45 is just a callable. It is not really executed unless you really start the execution. And that's exactly what run() is for.

So unless you don't explicitly start your thread, nothing of the FutureTask is called. And get() is designed to wait until a thread is finished. So, normally, you're starting a task (using run()), do some other stuff and later get the result using get() or wait there, if the task takes more time than expected.

you could check that, e.g. by running some System.out:

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

you won't see the anything

Upvotes: 2

Sorin
Sorin

Reputation: 1027

From the API of FutureTask:

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.

As such, run() will actually run your FutureTask and eventually arrive at a computation result. get() on the other Hand gives you the result, if the computation finished. But it doesn't start the computation and doesn't call run() itself.

See also @Zabuzard's comment:

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.

Upvotes: 3

Zabuzard
Zabuzard

Reputation: 25923

run vs get

run is the method that actually starts the 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, i.e. until run is finished. This obviously implies that you call run somehow before or from a different thread.


ExecutorService and CompletableFuture

FutureTask is not really supposed to be used directly by a user. It is more the type of class that is used behind the curtain in order to realize a nice async-API. More specifically, it is the base implementation for Future, as for example returned by ExecutorService when you spawn tasks with it.

Instead you should look into ExecutorService

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

and CompletableFuture

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

for an easy to use interface to spawn async tasks.

CompletableFutures have the advantage that you can also setup a pipeline of operations that are all executed asynchronously once the previous operation has finished. So for example:

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

Upvotes: 4

Related Questions