Java Concurrency
What is the difference between ReentrantLock and synchronized?
synchronized is Java's built-in locking mechanism. ReentrantLock gives similar mutual exclusion but adds more control, such as tryLock, timed waits, interruptible locking, fairness, and explicit unlock behavior.
The Short Answer
synchronizedis Java's built-in locking mechanism. It is simple, automatic, and great when you just need to protect a critical section.
ReentrantLock gives you more control: timed lock attempts, interruptible waiting, optional fairness, and explicit locking/unlocking. It has the same basic mutual-exclusion idea as synchronized, but with extended capabilities.
The Mental Model
synchronized
Automatic Door Lock
Java handles lock release automatically when the synchronized block exits.
ReentrantLock
Manual Industrial Lock
You control when the lock is acquired and released. That gives flexibility, but forgetting unlock can break the program.
Basic Code Comparison
With synchronized method:
private int count = 0;
public synchronized void increment() {
count++;
}Or with a synchronized block:
private final Object lock = new Object();
private int count = 0;
public void increment() {
synchronized (lock) {
count++;
}
}With ReentrantLock:
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}Why ReentrantLock Exists
If synchronized already works, why have ReentrantLock? Because some systems need more control than “wait until the lock is available.”
Timeout
Try to get the lock, but give up after a limit.
Interruptible Wait
Let a waiting thread be interrupted instead of waiting forever.
Fairness
Optionally give waiting threads a more queue-like ordering.
tryLock: The Big Practical Difference
With synchronized, if a thread reaches the lock, it waits until it can enter.
With ReentrantLock, you can ask: “Can I get the lock right now?” or “Can I get it within two seconds?”
if (lock.tryLock()) {
try {
// critical section
} finally {
lock.unlock();
}
} else {
// lock was busy, do something else
}if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
// critical section
} finally {
lock.unlock();
}
} else {
// could not acquire lock within timeout
}The timed version of tryLock allows a thread to wait for a limited amount of time before giving up. This is useful when waiting forever would be undesirable or dangerous.
Timeout Locking
What Does Reentrant Mean?
Reentrant means the same thread can acquire the same lock more than once without deadlocking itself.
lock.lock();
try {
// same thread can acquire again
lock.lock();
try {
// nested protected work
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}The lock keeps a hold count. If the same thread locks twice, it must unlock twice before another thread can acquire it.
Fairness
ReentrantLock can be created as fair:
Lock lock = new ReentrantLock(true);A fair lock tries to grant access to the longest-waiting thread. This can reduce starvation, but it may reduce throughput because the system gives up some scheduling flexibility. Fair locks are usually more predictable, but often slightly slower than the default non-fair behavior.
Fair vs Non-Fair Lock
Fair
Non-Fair
Money Transfer Example
This connects directly to the account transfer problem. If you need to lock two accounts, you still need consistent lock ordering to avoid deadlock.
public void transfer(Account from, Account to, int amount) {
Account first = from.id() < to.id() ? from : to;
Account second = from.id() < to.id() ? to : from;
first.lock().lock();
try {
second.lock().lock();
try {
from.withdraw(amount);
to.deposit(amount);
} finally {
second.lock().unlock();
}
} finally {
first.lock().unlock();
}
}This is the ReentrantLock version of nested synchronized blocks. The idea is the same: acquire locks in a consistent order so two threads do not grab opposite locks and wait forever.
Interview-Friendly Explanation
When to Use Which
Use synchronized when...
- The critical section is simple.
- You do not need timeout behavior.
- You do not need fairness control.
- You want safer automatic lock release.
Use ReentrantLock when...
- You need tryLock.
- You need timed lock attempts.
- You need interruptible lock waits.
- You need fairness or Condition objects.
Common Interview Follow-Ups
Is ReentrantLock faster than synchronized?
Not automatically. Modern JVMs have optimized synchronized heavily. Choose based on needed behavior first, not assumed speed.
Can synchronized do tryLock?
No. synchronized waits until the monitor is available. ReentrantLock gives tryLock and timed tryLock.
What is the biggest danger of ReentrantLock?
Forgetting to unlock. That is why unlock belongs in a finally block.
What does fair locking mean?
A fair ReentrantLock tries to favor the longest-waiting thread, reducing starvation risk but often lowering throughput.