I am trying to understand the working of CompletableFuture
from Java 8. Below code works as expected
CompletableFuture.supplyAsync(() -> {
System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
return "str";
}).thenApply(str -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
return str;
}).thenApply(str1 -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
return str1;
}).thenAccept(str3 -> {
System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
});
System.out.println("Thread name " + Thread.currentThread().getName());
Output:
supplyAsync Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name main
thenApply Thread name main
thenAccept Thread name main
Thread name main
But when I put in some computation, it doesn't work as expected please correct me if I am missing something.
CompletableFuture.supplyAsync(() -> {
System.out.println("supplyAsync Thread name " + Thread.currentThread().getName());
long val = 0;
for (long i = 0; i < 1000000; i++) {
val++;
}
return "str";
}).thenApply(str -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
long val = 0;
for (long i = 0; i < 1000000; i++) {
val++;
}
return str;
}).thenApply(str1 -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
long val = 0;
for (long i = 0; i < 1000000; i++) {
val++;
}
return str1;
}).thenAccept(str3 -> {
System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
long val = 0;
for (long i = 0; i < 1000000; i++) {
val++;
}
});
System.out.println("Thread name " + Thread.currentThread().getName());
Output is:
supplyAsync Thread name ForkJoinPool.commonPool-worker-1
Thread name main
I agree that I am not joining the child thread to main thread. My understanding is child thread should print the statements independently of main thread. The question is why is it not printing at all.
The CompletableFuture. get() method is blocking. It waits until the Future is completed and returns the result after its completion.
Since Void can not be instantiated, you can only complete a CompletableFuture<Void> with a null result, which is exactly what you also will get when calling join() on the future returned by allOf() once it has been successfully completed. CompletableFuture<Void> cf = CompletableFuture.
While using Future, we do not get notified when it is complete neither does it provides us a callable method which will automatically be called when the result is available but CompletableFuture provides us with a lot of callable methods which can be used as per our use case.
A CompltableFuture is used for asynchronous programming. Asynchronous programming means writing non-blocking code. It runs a task on a separate thread than the main application thread and notifies the main thread about its progress, completion or failure.
Explanation
You're not joining the child thread ForkJoinPool.commonPool-worker-1
to the main thread. So it gets killed once thread main
finishes.
Solution
Try calling .join()
on your completable future at some point in your code. Note that this method is blocking the main
thread. So the execution after the join point will be suspended until the child thread finishes its execution.
CompletableFuture.supplyAsync(() -> {
System.out.println("=> supplyAsync Thread name " + Thread.currentThread().getName());
// ...
}).thenApply(str -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
// ...
}).thenApply(str1 -> {
System.out.println("thenApply Thread name " + Thread.currentThread().getName());
// ...
}).thenAccept(str3 -> {
System.out.println("thenAccept Thread name " + Thread.currentThread().getName());
// ...
}).join()
Will print:
supplyAsync Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name ForkJoinPool.commonPool-worker-1
thenApply Thread name ForkJoinPool.commonPool-worker-1
thenAccept Thread name ForkJoinPool.commonPool-worker-1
Thread name main
If you want the last System.out.println(...)
not depend from execution of the child thread then assign your CompletableFuture
to a variable and join it in the very end of main:
CompletableFuture<Void> future = CompletableFuture.supplyAsync(...) ... //
System.out.println("Thread name " + Thread.currentThread().getName());
future.join();
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