I have been trying to implement an asynchronous process, where the parent method calls a child method which would in-turn call three different methods. I want all of this process to be done asynchronously i.e. after these three calls in the child method are made in parallel the control should go back to the parent method and continue with the rest of its execution.
I have this code which when tested works fine.
public ReturnSomething parent(){
child();
...//rest to UI
}
private void child(){
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable service1 = () -> {
MyFileService.service1();
};
Runnable service2 = () -> {
MyFileService.service2();
};
Runnable service3 = () -> {
MyFileService.service3();
};
executorService.submit(service1);
executorService.submit(service2);
executorService.submit(service3);
}
Now, my lead is asking me to use this rather.
public ReturnSomething parent(){
child();
...//rest to UI
}
private void child(){
CompletableFuture.supplyAsync(() -> MyFileService.service1();
CompletableFuture.supplyAsync(() -> MyFileService.service2();
CompletableFuture.supplyAsync(() -> MyFileService.service3();
}
I understand that that CompletableFuture is new from Java 8, but how is the 2nd code better than the 1st? Since, for ExecutorService, I am not calling the "get()" method I would not be waiting for the aysnc response. So, can some one please explain what is the difference?
The ExecutorService executes a task and updates the result in the Future. A CompletableFuture introduced later in Java 8 implements the Future interface. So CompletableFuture contains all the functionalities provided by the Future interface. The CompletableFuture allows you to chain tasks together.
public interface ExecutorService extends Executor. An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks. An ExecutorService can be shut down, which will cause it to reject new tasks.
Executor just executes stuff you give it. ExecutorService adds startup, shutdown, and the ability to wait for and look at the status of jobs you've submitted for execution on top of Executor (which it extends). This is a perfect answer, short and clear.
The ExecutorService helps in maintaining a pool of threads and assigns them tasks. It also provides the facility to queue up tasks until there is a free thread available if the number of tasks is more than the threads available.
Functionally, the two approaches are more or less the same:
Technically, however, there are some subtle differences:
ForkJoinPool
. You would have to pass an executor as second argument of supplyAsync()
if you don't want that;CompletableFuture
API allows to easily chain more calls with thenApply()
, thenCompose()
etc. It is thus more flexible than the simple Future
returned by ExecutorService.submit()
;CompletableFuture
allows to easily return a future from your child()
method using return CompletableFuture.allOf(the previously created futures)
.Concerning readability, it's a matter of preference, but if you want equivalent code the CompletableFuture
approach might be considered a bit less readable once you have formatted it similarly. Compare:
executorService.submit(MyFileService::service1);
executorService.submit(MyFileService::service2);
executorService.submit(MyFileService::service3);
with
CompletableFuture.supplyAsync(MyFileService::service1, executorService);
CompletableFuture.supplyAsync(MyFileService::service2, executorService);
CompletableFuture.supplyAsync(MyFileService::service3, executorService);
You're not waiting for results in both cases.
The advantage of the second approach is simply less boilerplate. That's what runAsync()
and supplyAsync()
are good for.
But if you don't actually return any value, you should use runAsync()
What second approach also provides, is the ability to wait for all futures with CompletableFuture.allOf()
. Which is also doesn't exist in the first scenario.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With