In Java, asynchronous methods are methods that start a task and return immediately, allowing the program to continue executing without waiting for the task to finish. This is useful for I/O operations, network calls, or long-running computations.
Java provides several ways to implement asynchronous methods.
1️⃣ Using CompletableFuture
(Java 8+)
The modern and recommended approach for asynchronous programming in Java is CompletableFuture
.
import java.util.concurrent.CompletableFuture;
public class AsyncExample {
public static void main(String[] args) {
System.out.println("Start");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// Simulate long-running task
try { Thread.sleep(2000); } catch (InterruptedException e) {}
return "Hello from async task";
});
// Do other work while async task runs
System.out.println("Doing other work...");
// Get result (blocks only here if needed)
String result = future.join();
System.out.println(result);
System.out.println("End");
}
}
Output:
Start
Doing other work...
Hello from async task
End
supplyAsync()
→ runs a task asynchronously and returns aCompletableFuture
.join()
→ waits for the result (similar toget()
but wraps exceptions).
✅ Chaining Asynchronous Tasks
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + " World")
.thenAccept(System.out::println);
thenApply()
→ transforms the resultthenAccept()
→ consumes the result- Tasks are executed asynchronously, allowing non-blocking execution.
2️⃣ Using ExecutorService
import java.util.concurrent.*;
public class ExecutorExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {
Thread.sleep(2000);
return "Async Task Result";
});
System.out.println("Doing other work...");
System.out.println(future.get()); // blocks until result is ready
executor.shutdown();
}
}
submit()
→ executes the task asynchronously and returns aFuture
.get()
→ blocks until the task finishes.
3️⃣ Using @Async
in Spring Framework
In Spring, you can annotate methods with @Async
to run them asynchronously:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethod() throws InterruptedException {
Thread.sleep(2000);
return CompletableFuture.completedFuture("Hello from Spring Async");
}
}
- Requires
@EnableAsync
on a configuration class. - Spring handles the thread pool automatically.
4️⃣ Key Points
Aspect | Notes |
---|---|
Non-blocking | Asynchronous methods allow the program to continue without waiting. |
Return type | Often CompletableFuture<T> or Future<T> . |
Thread management | CompletableFuture uses ForkJoinPool.commonPool() by default; ExecutorService allows custom thread pools. |
Exception handling | Use handle() , exceptionally() , or whenComplete() for async error handling. |
Chaining | Tasks can be chained using thenApply , thenCompose , thenAccept . |
✅ Summary
- Asynchronous methods: Start a task and return immediately.
- Java options:
CompletableFuture
(modern, flexible, supports chaining)ExecutorService
/Future
(classic)@Async
in Spring (framework support for async execution)
- Useful for network calls, database operations, and long computations.