Java Asynchronous Programming: Five Implementation Methods Explained
This article introduces the concept of asynchronous programming in Java, compares it with synchronous execution, and provides detailed examples of five implementation approaches—thread creation, thread pool with Future, CompletableFuture, SpringBoot @Async, and Guava ListenableFuture—complete with code snippets and usage guidelines.
Java interview questions often ask about asynchronous operations, what they are, how they differ from synchronous execution, and how to implement them. This article explains the concept of async programming and presents five practical ways to achieve it in Java.
What Is Asynchronous?
In a synchronous user registration flow, the system must wait for the database insertion to finish before sending an SMS, causing the entire process to block if the database operation is slow. Asynchronous programming separates loosely coupled tasks, allowing the main flow to continue while non‑critical work runs in the background.
1. Thread‑Based Asynchronous
The simplest way to achieve async behavior in Java is to create a new Thread. With JDK 8+, lambda expressions make this concise.
public class AsyncThread extends Thread {
@Override
public void run() {
System.out.println("Current thread name:" + this.getName() + ", executing thread name:" + Thread.currentThread().getName() + "-hello");
}
}
public static void main(String[] args) {
// Simulate business logic
// ...
// Create and start async thread
AsyncThread asyncThread = new AsyncThread();
asyncThread.start();
}Creating a thread for each task can waste resources, so a thread pool is preferred.
2. Future‑Based Asynchronous
When the result of an asynchronous task is needed, the Future interface from the JUC package can be used. However, calling get() blocks the calling thread, which may defeat the purpose of async execution.
@Test
public void futureTest() throws Exception {
System.out.println("main function starts");
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(() -> {
System.out.println("===task start===");
Thread.sleep(5000);
System.out.println("===task finish===");
return 3;
});
// Integer result = future.get(); // blocks if result is needed
System.out.println("main function ends");
System.in.read();
}3. CompletableFuture Asynchronous
CompletableFuture(introduced in JDK 1.8) builds on the Future and CompletionStage interfaces, offering a non‑blocking, callback‑driven API.
CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> factorial(number));
while (!completableFuture.isDone()) {
System.out.println("CompletableFuture is not finished yet...");
}
long result = completableFuture.get();Internally it uses a ForkJoinPool, so no explicit ExecutorService is required.
4. SpringBoot @Async Asynchronous
SpringBoot simplifies async execution with the @Async annotation. Enable it with @EnableAsync and optionally define a custom thread pool.
@SpringBootApplication
@EnableAsync
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}Custom thread‑pool configuration:
@Configuration
@Slf4j
public class ThreadPoolConfiguration {
@Bean(name = "defaultThreadPoolExecutor", destroyMethod = "shutdown")
public ThreadPoolExecutor systemCheckPoolExecutorService() {
return new ThreadPoolExecutor(3, 10, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10000),
new ThreadFactoryBuilder().setNameFormat("default-executor-%d").build(),
r -> log.error("system pool is full! "));
}
}Mark a method with @Async("defaultThreadPoolExecutor") to run it asynchronously:
@Service
public class AsyncServiceImpl implements AsyncService {
@Async("defaultThreadPoolExecutor")
public Boolean execute(Integer num) {
System.out.println("Thread:" + Thread.currentThread().getName() + " , task:" + num);
return true;
}
}5. Guava Asynchronous
Guava provides ListenableFuture for async tasks with callback support.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
ExecutorService threadpool = Executors.newCachedThreadPool();
ListeningExecutorService service = MoreExecutors.listeningDecorator(threadpool);
ListenableFuture<Long> guavaFuture = service.submit(() -> factorial(number));
long result = guavaFuture.get();Conclusion
Asynchronous programming is increasingly important for I/O‑bound scenarios. The five methods described—raw threads, thread pools with Future, CompletableFuture, SpringBoot @Async, and Guava ListenableFuture —provide a range of options to improve performance and responsiveness in Java applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Mike Chen's Internet Architecture
Over ten years of BAT architecture experience, shared generously!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
