First, it should be noted that the example you have brought (based on your comment, it's page 208, listing 10.2) is a bad example - one that ends in a deadlock. The objects are not locked one after the other to prevent dynamic lock order deadlock, they are an example of where dynamic lock order will happen!
Now, you are suggesting locking on this
, but what is this this
anyway, and what is the scope of locking?
- It's clear that the same object has to be used for all operations - withdraw, deposit, transfer. If separate objects are used for them, then one thread could do a deposit on account A, while another thread transfers from account A to account B, and they won't be using the same lock so the balance will be compromised. So the lock object for all accesses to the same account should be the same one.
- As Nathan Hughes explained, one needs to localize the locking. We can't use one central lock object for all the accounts, or we'll have them all waiting for each other despite not actually working on the same resources. So using a central locking object is also out of the question.
So it appears that we need to localize the locks so that each account's balance will have its own lock, so as to allow parallel operations between unrelated accounts, but that this lock has to be used for all operations - withdraw, deposit and transfer.
And here comes the problem - when it's just withdraw or deposit, you are operating on just one account, and so you need to just lock that account. But when you transfer, you have two objects involved. So you need to have both their balances locked in case there are other threads that want to operate on either.
Any object that holds a single lock for two or more accounts will break one of the two points above. Either it won't be used for all operations, or it will not be localized enough.
This is why they are attempting to lock the two locks one after another. Their solution was to make the Account
object itself the lock for the account - which fulfils both the "all operations" condition and the "locality" condition. But still we need to make sure we have the locks for both accounts before we can transfer the money.
But again, this source is an example of a deadlock prone code. This is because one thread may want to transfer from account A to account B, while another will want to transfer from account B to account A. In that case, the first one locks the A account, the second locks the B account, and then they are deadlocked because they have performed the locking in opposite order.