Java Threading
I craft this post by guiding AI with my thought process, questions, and tailored guidelines to generate meaningful content. After the AI…
Java Threading
I craft this post by guiding AI with my thought process, questions, and tailored guidelines to generate meaningful content. After the AI works its magic, I carefully organize the output, weaving ideas together to create a seamless, engaging narrative that’s easy to follow and memorable.
Thread Lifecycle

Java evolved from raw threads (1.4) → high-level executors & locks (5) → parallelism (7) → async/functional (8) → virtual threads (19+) and structured concurrency (21+). Choose based on workload: I/O → virtual threads; CPU → Fork/Join; coordination → StructuredTaskScope


Synchronized works
Every Java object has a monitor lock (also called an intrinsic lock).When a thread enters a synchronized method/block, it must first acquire the lock on that object.When the thread exitsThe lock is automatically released (even if an exception occurs).
In Java, synchronized is used to ensure that only one thread can execute a particular piece of code (called a critical section) at a time.It’s how you prevent race conditions when multiple threads access shared data.In simple terms:
✅ synchronized → acquires a lock (monitor) before running, and releases it after finishing.
Where can we use synchronized

What is an interruption in Java
An interruption is a signal sent to a thread telling it:
“Hey, you should stop what you’re doing soon — someone wants you to stop or wake up.”
It’s not a forceful kill (Java doesn’t kill threads directly). It’s more like politely tapping the thread on the shoulder.
Why do we need interruptions? Because threads often:
- wait,
- sleep,
- or block on I/O or locks
and you may need to cancel or stop them safely from another thread.
Since Java doesn’t let you forcibly kill a thread (for safety reasons),
you signal it with interrupt(), so the thread can stop itself.
Because forcefully killing a thread is dangerous:
- It can leave shared data half-written.
- It can lock resources permanently.
- It can break other running threads.
So Java says:
“Threads should stop themselves when they’re ready — not be killed by others.”
That’s what interruption enables — graceful cancellation.
What happens when you call thread.interrupt()
/** -------- 1 ---------- **/
// causes an InterruptedException immediately
Thread.sleep(1000);
/** -------- 2---------- **/
// here nothing will happen with interruption.But we can conditionaly check
// whether thread got interupted and work gracefully
while (true) {
if (Thread.currentThread().isInterrupted()) break;
else
// doing work load
}
Disadvantage of Synchronized code
1. Coarse-grained
Meaning: You lock the ENTIRE object/method, not just the 2 lines that really need protection.
→ One thread doing sendToKafka() blocks 1000 other threads that just want to do count++.
public class BadCounter {
private int count = 0;
private List<String> logs = new ArrayList<>();
public synchronized void incrementAndLog(String msg) {
count++; // needs lock for 0.0001 ms
logs.add(msg); // needs lock for 0.001 ms
sendToKafka(msg); // takes 50 ms (network!)
}
}
2. Blocking
Meaning: The thread goes to sleep → wastes OS thread.
Real numbers that scare managers:
- 1 OS thread ≈ 1–2 MB stack
- 10,000 concurrent requests → 10–20 GB RAM → AWS bill explodes
- Tomcat default max threads = 200 → 201st user gets 503
→ 200 users click → server dies in 2 minutes.
@GetMapping("/report")
public synchronized Report generate() {
Thread.sleep(30_000); // 30-second report
return report;
}
3. Deadlock-prone
Meaning: Two threads waiting for each other forever.
class Account {
synchronized void transfer(Account to, int amt) {
this.balance -= amt;
to.deposit(amt); // calls to's synchronized method
}
synchronized void deposit(int amt) { balance += amt; }
}
// Thread-1: a.transfer(b, 100)
// Thread-2: b.transfer(a, 200) → DEADLOCK!
How to kill deadlock in real projects:
- Always lock in global order (by accountId.hashCode())
- Use ReentrantLock.tryLock(5, SECONDS)
- Never call external service inside synchronized
4. No fairness
Meaning: Starvation is possible.
→ 100 threads hammering → one unlucky thread can wait forever.
synchronized void increment() { count++; }

2. Java 5 — java.util.concurrent (JUC) — The Big Leap
2.1 Executor Framework
Execute service is a “Thread Manager” — instead of creating threads manually, you give tasks to ExecutorService, and it runs them using threads behind the scenes.You just submit tasks. It handles threads for you.
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("Task"));
executor.shutdown();



NOTE :
Stop making threads yourself. Use ExecutorService — it’s smarter, safer, cleaner.
2.2 Explicit Locks (ReentrantLock)



2.3 ReadWriteLock

What is ReadWriteLock?
“Two locks in one”
- Read Lock → Many threads can read at the same time
- Write Lock → Only one thread can write, and no one can read
“If many threads can read at the same time, why do we even need a readLock()?”
We need readLock() to prevent writers from changing data while someone is reading.
Even though readers don’t block each other, they must block writers — and readLock() is how we do that.
2.4 Atomic Variables
No explicit synchronization — uses CAS (Compare-And-Swap)



2.5 Concurrent Collections


3. Java 7 — Parallelism Boost
3.1 Fork/Join Framework

Fork/Join = Split → Parallel → Join.
Perfect for CPU-heavy tasks on multi-core machines.
Uses all CPU cores automatically.
Perfect for divide-and-conquer tasks.

class MyTask extends RecursiveTask<Result> {
protected Result compute() {
if (small) {
return solveDirectly();
} else {
MyTask left = new MyTask(...);
MyTask right = new MyTask(...);
left.fork();
return right.compute() + left.join();
}
}
}
// Run:
ForkJoinPool pool = new ForkJoinPool();
Result r = pool.invoke(new MyTask());
4. Java 8 — Functional & Async
4.1 Parallel Streams
long sum = Arrays.stream(numbers)
.parallel()
.filter(n -> n % 2 == 0)
.sum();
4.2 CompletableFuture — Async Non-blocking
CompletableFuture = Run task in background + do something when done — without blocking thread!


5. Java 19+ — Virtual Threads (Project Loom) — Game Changer
5.1 Lightweight Threads (1:1 → M:N)
Write Synchronous Code — Get Async Performance





How to Use
// Option 1: Simple
Thread.startVirtualThread(() -> {
System.out.println("I'm virtual!");
});
// Option 2: Builder
Thread t = Thread.ofVirtual().name("worker-1").start(() -> {
// work
});
// Option 3: In Executors
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100_000; i++) {
executor.submit(() -> {
Thread.sleep(1000);
System.out.println("Task " + Thread.currentThread());
});
}
} // Auto shutdown
Virtual Thread vs CompletableFuture


Java 21+ — Structured Concurrency
What is Structured Concurrency?
“Run multiple tasks together — like a family — and manage them as one unit.”
Think of it like raising children:
- You start 3 tasks (kids)
- They can play in parallel
- But all finish before you leave the park
- If one cries (fails), all stop
- If you cancel, all come back

record Profile(String name, String email) {}
record Orders(List<String> items) {}
record Balance(double amount) {}
static String getUserDetails(String userId) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<Profile> profile = scope.fork(() -> fetchProfile(userId));
Future<Orders> orders = scope.fork(() -> fetchOrders(userId));
Future<Balance> balance = scope.fork(() -> fetchBalance(userId));
scope.join(); // Wait for all 3
scope.throwIfFailed(e -> new WebApplicationException("Failed", 500));
return """
Name: %s
Email: %s
Orders: %s
Balance: %.2f
""".fprintf(
profile.resultNow().name(),
profile.resultNow().email(),
orders.resultNow().items(),
balance.resultNow().amount()
);
}
}




Hands on Samples
https://github.com/dilhan80/code-practice/tree/main/thread-practice
References
메타데이터
- post_id
- 4a019e98a2c5
- slug
- java-threading-4a019e98a2c5
- url
- https://medium.com/@dilhanariyarathna/java-threading-4a019e98a2c5
- canonical_url
- https://medium.com/@dilhanariyarathna/java-threading-4a019e98a2c5
- author_url
- https://medium.com/@dilhanariyarathna
- status
- ok
- fetched_at
- 2026-08-02 01:07:48