Please read the question carefully before marking this as duplicate.
Below is the snippet of the pseudo code. My question is- Does the below code not defeat the very notion of parallel asynchronous processing?
The reason I ask this is because in the below code the main thread would submit a task to be executed in a different thread. After submitting the task in the queue, it blocks on Future.get() method for the task to return the value. I would rather have the task executed in the main thread rather than submitting to a different thread and waiting for the results. What is that I gained by executing the task in a new thread?
I am aware that you could wait for a limited time etc, but then what if I really care about the result? The problem gets worse if there are multiple tasks to be executed. It seems to me that we are just doing the work synchronously. I am aware of the Guava library which provides a non blocking listener interface. But I am interested to know if my understanding is correct for the Future.get() API. If it is correct, why is the Future.get() designed to block thereby defeating the whole process of parallel processing?
Note - For the record, I use JAVA 6
public static void main(String[] args){
private ExectorService executorService = ...
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());
}
I would like to give my share on this one, more on theoretical point of view as there are some technical answers already. I would like to base my answer on the comment:
which agrees with what is said in the question.
Say you have three kids, and you want to make a cake, for your birthday. Since you want to make the greatest of cakes you need a lot of different stuff to prepare it. So what you do is split the ingredients on three different lists, because where you live there exist just 3 supermarkets that sell different products, and assign each of your kids a single task,
simultaneously
.Now, before you can start preparing the cake (let's assume again, that you need all the ingredients beforehand) you will have to wait for the kid that have to do the longest route. Now, the fact that you need to wait for all the ingredients before starting to make the cake is your necessity, not a dependency among tasks. Your kids have been working on the tasks simoultaneously as long as they could (e.g: until the first kid completed the task). So, to conclude, here you have the paralelilsm.
The sequential example is described when you have 1 kid and you assign all three tasks to him/her.
In the example you have given you might as well run everything in your
main()
method and go your merry way.But let us assume you have three steps of computation that you are currently running sequentially. Just for understanding let us assume that step1 takes t1 seconds, step2 takes t2 seconds, and step3 takes t3 seconds to complete. So total computation time is
t1+t2+t3
. Also, let us assume thatt2>t1>=t3
.Now let us consider a scenario when we executed these three steps in parallel using
Future
to hold each computational results. You can check if each task is done using non-blockingisDone()
call on corresponding futures. Now what happens? theoretically your execution is as fast as howt2
completes right? So we did gain some benefits from parallelism.Also, in Java8 , there is
CompletableFuture
that supports functional style call backs.Future
offers you methodisDone()
which is not blocking and returns true if computation has completed, false otherwise.Future.get()
is used to retrieve the result of computation.You have a couple of options:
isDone()
and if the result is ready ask for it by invokingget()
, notice how there is no blockingget()
get(long timeout, TimeUnit unit)
The whole
Future API
thing is there to have easy way obtaining values from threads executing parallel tasks. This can be done synchronously or asynchronously if you prefer, as described in bullets above.UPDATE WITH CACHE EXAMPLE
Here is a cache implementation from Java Concurrency In Practice, an excellent use case for
Future
.Future
for other callers.This is all easily achieved with
Future
API.It all depends on your use case:
get()
get()
with time-outIf you can continue without analysing the result immediately and inspect the result at future time, use CompletableFuture (java 8)
You can implement callback mechanism from your Runnable/Callable. Have a look at below SE question:
Java executors: how to be notified, without blocking, when a task completes?
If you don't care about the results, then spawn a new thread and from that thread use
ExectorService
API for task submission. In that way, your parent thread i.emain
thread will not be blocking in any way, it would simply spawn a new thread and then will start further execution, while the new thread will submit your tasks.For creating new thread - either do it yourself by having a
ThreadFactory
for your async thread creation or use some implementation ofjava.util.concurrent.Executor
.If this is in a JEE application and you are using Spring framework then you can easily create a new asynchronous thread using
@async
annotation.Hope this helps!