Non-Blocking Concurrency Models
Traditional Java threading approaches like extending Thread or implementing Runnable lack result retrieval capabilities. The Future interface represents asynchronous task results, but requires blocking checks to completion.
interface Future<V> {
boolean cancel(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
CompletableFuture Fundamentals
CompletableFuture implements both Future and CompletionStage interfaces, enabling non-blocking asynhcronous operations through callback chaining and compositoin.
Basic Usage Examples
// Manual completion
CompletableFuture<String> manualFuture = new CompletableFuture<>();
new Thread(() -> {
sleepSeconds(2);
manualFuture.complete("Operation succeeded");
}).start();
System.out.println(manualFuture.get());
// Void asynchronous task
CompletableFuture.runAsync(() -> {
System.out.println("Executing void task");
sleepSeconds(1);
}).get();
// Result-bearing task
CompletableFuture<String> resultFuture = CompletableFuture.supplyAsync(() -> {
sleepSeconds(1);
return "Result";
});
System.out.println(resultFuture.get());
Callback Chaining
// Transformation pipeline
CompletableFuture.supplyAsync(() -> "42")
.thenApply(Integer::parseInt)
.thenApply(val -> val * 2)
.thenAccept(System.out::println)
.join();
// Terminal operations
CompletableFuture.supplyAsync(() -> "Data")
.thenRun(() -> System.out.println("Processing complete"));
Task Composition
// Dependent tasks
CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> composed = first.thenCompose(s ->
CompletableFuture.supplyAsync(() -> s + " World"));
System.out.println(composed.get());
// Independent task combination
CompletableFuture<Double> tempFuture = CompletableFuture.supplyAsync(() -> 22.5);
CompletableFuture<Double> humidityFuture = CompletableFuture.supplyAsync(() -> 65.0);
tempFuture.thenCombine(humidityFuture, (t, h) -> t + "C/" + h + "%")
.thenAccept(System.out::println);
Multiple Task Handling
// All tasks completion
CompletableFuture<?>[] tasks = IntStream.range(0, 5)
.mapToObj(i -> CompletableFuture.supplyAsync(Math::random))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(tasks).join();
List<Double> results = Stream.of(tasks)
.map(CompletableFuture::join)
.collect(Collectors.toList());
// First completed task
CompletableFuture<String> fastTask = CompletableFuture.supplyAsync(() -> {
sleepSeconds(1);
return "Fast";
});
CompletableFuture<String> slowTask = CompletableFuture.supplyAsync(() -> {
sleepSeconds(3);
return "Slow";
});
CompletableFuture.anyOf(fastTask, slowTask)
.thenAccept(System.out::println);
Error Handling
// Exception recovery
CompletableFuture.supplyAsync(() -> {
if (invalidInput) throw new IllegalArgumentException("Invalid");
return "Valid";
}).exceptionally(ex -> "Fallback: " + ex.getMessage())
.thenAccept(System.out::println);
// Universal handling
CompletableFuture.supplyAsync(() -> "Data")
.handle((res, ex) -> ex != null ? "Error" : res)
.thenAccept(System.out::println);
Key Methods
runAsync/supplyAsync: Initiate async tasksthenApply: Transform resultsthenAccept/thenRun: Final result processingthenCompose: Chain dependent futuresthenCombine: Merge independent futuresallOf/anyOf: Multiple future coordinationexceptionally/handle: Error recovery