How does ReentrantLock differ from the synchronized keyword?
ReentrantLock provides several capabilities that plain synchronized does not offer. tryLock() attempts to acquire the lock without blocking at all, and tryLock(timeout) gives up and returns false after a specified wait period instead of blocking indefinitely. lockInterruptibly() allows a thread that is currently waiting for the lock to be interrupted and abort the wait. A ReentrantLock can also be constructed in fair mode, with new ReentrantLock(true), which serves waiting threads strictly in the order they requested the lock rather than allowing arbitrary jumping of the queue. It also supports multiple independent Condition objects tied to the same lock, which lets you maintain separate wait-sets, for example one for producers and one for consumers, and wake only the relevant group with signal() instead of always waking everyone with signalAll(). It additionally exposes introspection methods to query the lock's current state. The tradeoff is that, unlike synchronized, ReentrantLock is never released automatically, so you must always call unlock() inside a finally block to avoid leaking the lock if an exception is thrown.
Ready to master this question?
Generate a complete walkthrough — background, the full answer in plain language, a working code example explained line by line, a real-world scenario, common mistakes, and how this same question gets asked in different ways.
Sign in to generate a response