In synchronous programming, tasks are executed one after another, in a strict sequence.
Each task must complete before the next task starts.
The executing thread waits (blocks) until the current operation finishes.
- Sequential execution
- Blocking in nature
- Simple control flow
- Easy to reason about
- Poor resource utilization for slow operations
public class SyncExample {
public static void main(String[] args) {
System.out.println("Task 1 started");
slowOperation();
System.out.println("Task 2 started");
}
static void slowOperation() {
try {
Thread.sleep(3000); // simulating delay
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}Task 1 started
(wait 3 seconds)
Task 2 started
The program halts execution until slowOperation() completes.
-
CPU stays idle during I/O wait
-
Poor scalability
-
Slow response time
-
Not suitable for:
- Network calls
- File I/O
- Database queries
- UI applications
- High-traffic servers
In asynchronous programming, tasks are initiated, but execution does not wait for completion.
The task runs in the background, and the result is handled later.
The main thread continues execution without blocking.
- Non-blocking execution
- Better CPU utilization
- Improved performance and responsiveness
- Requires callbacks, futures, or promises
- Slightly more complex control flow
ExecutorService executor = Executors.newSingleThreadExecutor();
System.out.println("Task 1 started");
executor.submit(() -> {
Thread.sleep(3000);
System.out.println("Async Task completed");
return null;
});
System.out.println("Task 2 started");
executor.shutdown();Task 1 started
Task 2 started
(wait 3 seconds)
Async Task completed
Main thread does not wait for the background task.
future.get(); // blocks thread- Thread waits
- CPU idle
- Simple but inefficient
future.thenAccept(result -> System.out.println(result));- Thread continues execution
- CPU stays productive
- Better performance
Task A → Finish → Task B → Finish → Task C
Task A → Task B → Task C
↘
Async Task (runs independently)
Examples:
- Normal method calls
- File I/O (traditional)
- JDBC (blocking calls)
Thread.sleep()
int result = compute(); // blockingExamples:
ThreadExecutorServiceFutureCompletableFuture- Reactive APIs
CompletableFuture
.supplyAsync(() -> compute())
.thenAccept(result -> System.out.println(result));You order food and stand at the counter until it’s ready.
You can’t do anything else while waiting.
You order food, get a token, and do other work. You’re notified when food is ready.
This is how modern servers work.
- One thread per request
- Threads blocked during I/O
- Poor scalability
- High memory usage
- Threads reused efficiently
- Non-blocking I/O
- Handles more requests with fewer threads
- High scalability
- Simple scripts
- CPU-bound tasks
- Small applications
- Linear business logic
- Easy debugging required
- Network calls
- REST APIs
- Database operations
- File uploads/downloads
- Microservices
- High-traffic backend systems
- UI applications
| Aspect | Synchronous | Asynchronous |
|---|---|---|
| Execution | Sequential | Concurrent |
| Blocking | Yes | No |
| Thread usage | Inefficient | Efficient |
| Complexity | Low | Medium–High |
| Scalability | Poor | Excellent |
| Performance | Lower | Higher |
| Debugging | Easier | Harder |
-
Asynchronous ≠ Multithreading (Async can use threads, but concept is about non-blocking)
-
Asynchronous ≠ Parallel (Async tasks may not run at the same time)
Execution where each task waits for the previous task to finish.
Execution where tasks run independently without blocking the main thread.
No. It focuses on non-blocking execution, not thread count.
Because it prevents threads from blocking during wait time.
Synchronous programming.
-
Synchronous programming is simple but blocking
-
Asynchronous programming is non-blocking and scalable
-
Async improves CPU utilization and throughput
-
Modern backend systems rely heavily on async models
-
Java supports async via
ExecutorService,Future, andCompletableFuture