Card 02/ 08
Deadlock Example: A Transfer Run in Both Directions at Once
Two correct, careful transfers lock the same two accounts in opposite orders.
Two pieces of code that each take the same two locks, in opposite orders, can deadlock against each other. A transfer that locks both accounts before moving money does exactly that when two transfers run in opposite directions at the same time.
The transfer locks the account it takes from, then the account it pays into:
void transfer(Account from, Account to, long pence) {
synchronized (from) {
synchronized (to) {
from.withdraw(pence);
to.deposit(pence);
}
}
}Two transfers start at once, one from Alice to Bob and one from Bob to Alice:
new Thread(() -> transfer(alice, bob, 100)).start();
new Thread(() -> transfer(bob, alice, 50)).start();The first thread takes Alice's lock and wants Bob's. The second takes Bob's and wants Alice's. Both are inside line 2 and stuck on line 3, and both accounts stay locked for the rest of the process's life.
Neither thread did anything wrong. Each locked everything it needed before touching anything, which is the usual advice, and the advice is not enough on its own: the two threads locked the same two objects in opposite orders.
← → move through sections and cards