Card 06/ 09
synchronized vs ReentrantLock
The keyword releases itself; the class can time out, be interrupted and be released elsewhere.
ReentrantLock is a class that does what the synchronized keyword does, through method calls, and adds several things the keyword cannot express. Both are reentrant (a thread may take a lock it already holds) and both give the same exclusion and visibility, meaning a thread that takes the lock sees every write made under it; the table compares what else each can do, and the rule after it says which to use.
| Compared on | synchronized | ReentrantLock |
|---|---|---|
| Released automatically | Yes, on every exit from the block | No: needs a finally |
| Give up after a timeout | No | tryLock(5, SECONDS) |
| Give up immediately if held | No | tryLock() |
| Interruptible while waiting | No | lockInterruptibly() |
| Acquire in one method, release in another | No | Yes |
| Fairness, first come first served | No | Optional, at a cost |
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 rows the keyword cannot do, and most often the one you need is the timeout on waiting.
← → move through sections and cards