Card 05/ 09
Reentrant Locks: Taking a Lock the Thread Already Holds
A synchronized method can call another on the same object without deadlocking itself.
Java's locks are reentrant: they are held by a thread, not by a block of code, so a thread that already holds a lock may take it again. The lock keeps a count, and it is released only when the count returns to zero.
A synchronized method calls another synchronized method on the same object. The second needs the lock the first is holding, and the thread does not wait for itself:
class Account {
synchronized void withdraw(long amount) {
if (amount <= balance()) { pence -= amount; }
}
synchronized long balance() { return pence; }
}Entering withdraw takes the lock, and the count is 1. Calling balance() takes it again, and the count is 2. Leaving balance() brings it back to 1, and leaving withdraw releases the lock for other threads.
Without reentrancy, a class could not call its own synchronized methods, and a subclass overriding a synchronized method could not call super. Both would block forever on a lock the same thread held.
So keep synchronized regions short and keep foreign calls out of them. Gather what you need under the lock, release it, and then call whatever needs calling.
← → move through sections and cards