synchronized and ReentrantLock are both Java locking mechanisms for mutual exclusion, but ReentrantLock is a more flexible, explicit API that offers capabilities the simpler synchronized keyword doesn't provide.
Key Points: • synchronized locks and unlocks automatically at block/method boundaries, even across exceptions, with no chance of forgetting to release the lock. • ReentrantLock requires explicit lock() and unlock() calls, typically wrapped in a try/finally to guarantee release. • ReentrantLock supports tryLock() with optional timeouts, letting a thread give up instead of waiting forever for a contended lock. • ReentrantLock supports lockInterruptibly(), allowing a thread blocked on a lock to respond to interruption. • ReentrantLock supports a fairness policy (constructor flag) and multiple Condition objects per lock, enabling more nuanced wait/notify style coordination than a single monitor allows.
Example: A connection pool that wants to give up waiting for a lock after 500ms rather than blocking indefinitely would use lock.tryLock(500, TimeUnit.MILLISECONDS), something synchronized simply cannot express.
Code Example:
private final ReentrantLock lock = new ReentrantLock();
public void update() {
lock.lock();
try {
// critical section
} finally {
lock.unlock();
}
}Interview Tip: A concise interview answer is:
"synchronized is simpler and safer by default since the JVM handles lock release automatically, even on exceptions. ReentrantLock trades that simplicity for more control — tryLock with timeouts, interruptible locking, fairness policies, and multiple conditions per lock — which matters for more advanced concurrency scenarios."