Reputation:
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
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
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
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.
CompletableFuture
s 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