Card 06/ 09

ComparisonDifficulty: Advanced1 min

synchronized Against ReentrantLock

ReentrantLock does what synchronized does, with a method call instead of a keyword, and adds four things the keyword cannot express.

The two locking mechanisms, on what each can express
Compared onsynchronizedReentrantLock
Released automaticallyYes, on every exit from the blockNo — needs a finally
Give up after a timeoutNotryLock(5, SECONDS)
Give up immediately if heldNotryLock()
Interruptible while waitingNolockInterruptibly()
Acquire in one method, release in anotherNoYes
Fairness, first come first servedNoOptional, at a cost
java
private final ReentrantLock lock = new ReentrantLock();

void withdraw(long amount) {
    lock.lock();
    try {
        if (amount <= pence) { pence -= amount; }
    } finally {
        lock.unlock();
    }
}

The finally is not optional and not a style choice. Without it, an exception inside the block leaves the lock held forever and every other thread waits on it for the life of the process.

The decision rule. Use synchronized by default — it cannot be left unreleased, and it is shorter. Reach for ReentrantLock when you need one of the four rows the keyword cannot do, and most often that row is the timeout.