multi threading
advancedLocks & Synchronizers
Use explicit locks (ReentrantLock, ReadWriteLock) and synchronizers (Semaphore, CountDownLatch, CyclicBarrier) when synchronized isn't enough.
synchronized is Java's simplest way to stop two threads entering the same code at once. The classes in java.util.concurrent.locks do the same job and add things synchronized cannot do.
ReentrantLock = a room key with a timer (give up if waiting too long). ReadWriteLock = a library reading room (many readers, one writer). Semaphore = a parking lot with K spots. CountDownLatch = a starting gun (wait until ready). CyclicBarrier = relay runners meeting at each lap.
Key Concepts
1
What synchronized cannot do. It cannot give up after waiting a while. It cannot check whether a lock
is free without waiting for it. It cannot be interrupted. And it cannot let many readers in while keeping
writers out.
synchronized
2
ReentrantLock does all four:
ReentrantLock
3
if (lock.tryLock()) { ... } // take it only if free
if (lock.tryLock(2, TimeUnit.SECONDS)) { ... } // give up after 2s
lock.lockInterruptibly(); // cancellable4
The cost is that you must release it yourself.
lock.lock();
try {
// work
} finally {
lock.unlock(); // an early return without this hangs everything
}5
synchronized releases automatically when the block ends. With a lock, a return that skips unlock()
leaves every waiting thread stuck forever.
synchronizedreturnunlock()
6
Fairness sounds good and costs a lot. A fair lock hands itself to whoever has waited longest. That
prevents an unlucky thread waiting forever, and it is significantly slower, because the fast path — letting
whoever is ready go first — is exactly what fairness forbids.
7
Use it only when a starved thread is a real problem.
8
Read-write locks help only when reads dominate. Many threads can hold the read lock at once; a writer
excludes everyone. If writes are frequent, the extra bookkeeping makes it slower than a plain lock.
9
The coordination classes each answer a different question.
CountDownLatch(3) wait for 3 EVENTS to happen. One-shot, never
resets. "wait until all services are ready"
CyclicBarrier(3) wait for 3 THREADS to arrive, then release them
all. Resets. "finish round 1 before round 2"
Semaphore(10) allow 10 at a time. "at most 10 calls to the
payment provider at once"10
The latch counts events and cannot be reused. The barrier counts threads and can. That is the difference
interviewers test.
11
Conditions replace wait/notify and improve on them. One lock can have several conditions:
waitnotify
12
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();13
A producer signals notEmpty; a consumer signals notFull. Only the threads that care wake up. With
synchronized you have notifyAll, which wakes everyone to check and go back to sleep.
notEmptynotFullsynchronizednotifyAll
14
Always wait inside a loop.
while (queue.isEmpty()) {
notEmpty.await(); // NOT if (...)
}15
A thread can wake up without being signalled — the specification permits it — and the condition may have
changed between the signal and this thread reacquiring the lock. Checking once is not enough.
16
What the interviewer is probing.1. "Why use ReentrantLock over synchronized?" Probing: the capabilities. Stalls: "It is
faster." Moves up: timeouts, try-lock, interruption, fairness and multiple conditions.
ReentrantLocksynchronized
17
2. "CountDownLatch or CyclicBarrier?" Probing: precision. Stalls: "They both wait." Moves up:
events versus threads, one-shot versus reusable, with an example of each.
CountDownLatchCyclicBarrier
18
3. "When does a read-write lock lose?" Probing: whether you know it is not free. Stalls: "It is
always better for reads." Moves up: frequent writes make the bookkeeping cost more than it saves.
19
4. "Limit calls to a service to ten at a time." Probing: picking the right tool. Stalls: a
synchronized counter. Moves up: a Semaphore(10), acquired and released in a finally.
Semaphore(10)finally
20
5. "Why wait in a while loop?" Probing: spurious wakeups. Stalls: "Habit." Moves up: a thread
can wake without a signal, and the condition may have changed since.
while
21
Lock choice22
synchronized simplest; automatic release; no timeout, no
tryLock, not interruptible
ReentrantLock all of the above, plus fairness and Conditions;
YOU must unlock in finally
ReadWriteLock many readers OR one writer; wins only when reads
dominate
StampedLock adds optimistic reads (no lock taken, validate
after); NOT reentrant; Java 8+23
Synchronizers24
CountDownLatch(n) wait for n EVENTS; one-shot, never resets
"wait until all services report ready"
CyclicBarrier(n) wait for n THREADS; resets after each release
"all workers finish round k before round k+1"
Semaphore(n) n permits; caps concurrency
"at most 10 concurrent calls downstream"
Phaser barrier with dynamic registration
Exchanger two threads swap objects at a rendezvous25
The finally rule26
lock.lock();
try {
// critical section
} finally {
lock.unlock(); // an early return without this deadlocks
} // everything waiting behind it27
Condition over wait/notify28
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();29
// producer signals notEmpty, consumer signals notFull:
// exactly the waiters that care wake up, unlike notifyAll()30
while (queue.isEmpty()) notEmpty.await(); // ALWAYS in a loop