☕ Java
Synchronization in Java
When multiple threads share data, things can go silently wrong. Two threads updating the same counter? You'll lose increments. Two threads modifying the same bank balance? Money vanishes. Synchronization prevents these race conditions.
The Race Condition Problem
A race condition happens when the program's result depends on the timing of thread execution — and the timing is unpredictable.
Classic example: Two threads both read a counter (value: 100), both increment it, both write back. Both write 101. You expected 102 — you lost one increment.
Real-world consequences: In a ticket booking system, two users book the last seat simultaneously. Without synchronization, both get confirmed and you've sold the same seat twice.
Java
// Without synchronization — race condition!
class Counter {
private int count = 0;
public void increment() {
count++; // This is NOT atomic: it's read + add + write (3 steps)
}
public int getCount() { return count; }
}
Counter c = new Counter();
Thread t1 = new Thread(() -> { for (int i = 0; i < 10000; i++) c.increment(); });
Thread t2 = new Thread(() -> { for (int i = 0; i < 10000; i++) c.increment(); });
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(c.getCount());
// Expected: 20000. Actual: somewhere between 10000–20000. Non-deterministic!synchronized — The Fix
Java
// With synchronization — thread-safe!
class Counter {
private int count = 0;
// Only one thread can execute this method at a time
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
// Now the result is always exactly 20000
// Alternatively: synchronized block (more granular, less blocking)
class Counter2 {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) { // only lock for the critical section
count++;
}
// non-critical code here doesn't block other threads
}
}
// Modern alternative: java.util.concurrent.atomic
import java.util.concurrent.atomic.AtomicInteger;
AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet(); // thread-safe, faster than synchronized