In the previous tutorial, I introduced to you all about the Future object in Java and I also told you that when using the get() method of the Future object, our program will be blocked until when all the tasks completed. To solve this blocking problem, from version 8, Java introduces the CompletableFuture object to help us solve this problem. How is it in details? Let’s find out in this tutorial.
To make it easier to compare the Future object and the CompletableFuture object, we will use the Future object as an example first.
My Callable object will have the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.huongdanjava.javaexample; import java.util.concurrent.Callable; public class Calculator implements Callable<Integer> { private int a; private int b; public Calculator(int a, int b) { this.a = a; this.b = b; } public Integer call() throws Exception { Thread.sleep(3000); return a + b; } } |
Notice that in the call() method of the Callable object, I am sleeping the code 3s to demo for long thread processing.
Now I will write a main class using the Future object. The code for this class is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.huongdanjava.javaexample; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Example { public static void main(String[] args) throws ExecutionException, InterruptedException { // Create thread pool using Executor Framework ExecutorService executor = Executors.newFixedThreadPool(10); // Create new Calculator object Calculator c = new Calculator(2, 3); Future<Integer> f = executor.submit(c); System.out.println(f.get()); System.out.println("End..."); executor.shutdown(); } } |
When running this example, you will see after 3 seconds we will get the result and then print the output and the “End ..” line is also output:
Now, I’m going to use the CompletableFuture object so that our program is not blocked and will get the same result as when using the Future object.
First, we need to submit the Calculator object to another thread first. CompletableFuture has many different methods that help us do this. In this tutorial, I will use the supplyAsync() method, which will help us get the results after completing the task.
The parameter of the supplyAsync() method is a Supplier interface so we need to modify the Calculator class implementing a Supplier interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.huongdanjava.javaexample; import java.util.function.Supplier; public class Calculator implements Supplier<Integer> { private int a; private int b; public Calculator(int a, int b) { this.a = a; this.b = b; } @Override public Integer get() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return a + b; } } |
And now in the main class, we do not need to use the Executor Framework anymore because CompletableFuture will do our job in another thread. The main class we can now rewrite is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.huongdanjava.javaexample; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class Example { public static void main(String[] args) throws ExecutionException, InterruptedException { // Create new Calculator object Calculator c = new Calculator(2, 3); CompletableFuture<Integer> f = CompletableFuture.supplyAsync(c); System.out.println("End..."); Thread.sleep(10000); } } |
To be able to retrieve the result after the execution of the task in the get() method of the Calculator object completed and print the output to the console, I will use the CompleTextFuture’s thenAccept() method with the parameter is a Consumer interface which will hold value after the task is finished.
The code of the main class will now look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.huongdanjava.javaexample; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class Example { public static void main(String[] args) throws ExecutionException, InterruptedException { // Create new Calculator object Calculator c = new Calculator(2, 3); CompletableFuture<Integer> f = CompletableFuture.supplyAsync(c); f.thenAccept(result -> { System.out.println(result); }); System.out.println("End..."); Thread.sleep(10000); } } |
When running the above code, you will see the line “End …” will be printed first. After 3 seconds, after processing the task, the result is returned and assigned to the result variable. At this point, the results will also be printed.
Obviously, our program is no longer blocked.