Thread Java 30 days- day 13 (CompletableFuture)
It is been a while since I last updated because I’ve been quite busy with work. I’ve recently developed a small tool related to threads, so today I’d like to introduce CompletableFuture.
CompletableFuture
is introduced in Java 8 as part of the java.util.concurrent
package. Java 8 introduced many new features and enhancements for handling asynchronous and concurrent programming, and CompletableFuture
is one of the key additions in this regard.
Example:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// Simulate a time-consuming operation, e.g., downloading a file
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Operation completed";
});
future.thenAccept(result -> {
System.out.println("Operation result: " + result);
});
System.out.println("Main thread continues to execute");
}
}
Purpose and Usage:
Runnable:
Runnable
is used to represent a task or action that can be executed in a separate thread. It defines a singlerun
method that you implement with the code you want to run asynchronously.- It’s simple and often used to create a new thread, execute a task, and that’s it. It doesn’t provide built-in mechanisms for handling the result of the task or dealing with exceptions.
CompletableFuture:
CompletableFuture
is a class in Java that is specifically designed for handling asynchronous operations and managing their results. It provides a higher level of functionality compared toRunnable
.- It allows you to create complex workflows of asynchronous operations, combine and chain them, specify how to handle their results, and deal with exceptions that might occur during the operation.
COMPLETABLEFUTURE COMBINE EXECUTORSERVICE
The difference between using CompletableFuture
with an ExecutorService
and without it lies in how you control and manage the execution of asynchronous tasks:
Using ExecutorService
:
- When you use
CompletableFuture
with anExecutorService
by passing it to methods likesupplyAsync
orrunAsync
, you have explicit control over which threads execute the asynchronous operations and how many threads are used. - You can create your own custom
ExecutorService
with specific configurations to meet your application's requirements, such as thread pool size and behavior.
Without ExecutorService
:
- If you don’t pass an
ExecutorService
toCompletableFuture
methods, it will use the defaultForkJoinPool
for executing asynchronous operations. - This approach is more straightforward, and you don’t need to configure a custom
ExecutorService
. - It’s suitable for most cases where you don’t require fine-grained control over thread management.
Using CompletableFuture
with an ExecutorService
provides explicit control over thread execution and is suitable when you need to fine-tune concurrency. On the other hand, not using an ExecutorService
lets you rely on the default ForkJoinPool
, which is more convenient for many typical scenarios without complex thread management needs.