Reputation: 44124
I have an object User with two locks, inventoryLock and currencyLock. Often these locks will be used individually, e.g.
synchronized (user.inventoryLock) {
// swap items
tmp = user.inventory[x];
user.inventory[x] = user.inventory[y];
user.inventory[y] = tmp;
}
or
synchronized (user.currencyLock) {
if (user.money < loss) throw new Exception();
user.money -= loss;
}
But sometimes a piece of code requires both locks:
synchronized (user.currencyLock) {
synchronized (user.inventoryLock) {
if (user.money < item.price) throw new Exception();
user.money -= item.price;
user.inventory[empty] = item;
}
}
Seems simple, but there are more bits of code using both locks than just this example, and I know from previous experience that if multiple pieces of code require the same shared locks, they have a risk of deadlocking.
What's a good way to avoid that?
Is there maybe some kind of mechanism that will let me atomically lock on two objects?
Upvotes: 0
Views: 161
Reputation: 3190
I don't see any circular wait possibilities here, which is 1 of 4 conditions necessary for deadlock.
Upvotes: 0
Reputation: 48226
always lock one lock before the other, one of the requirements of a deadlock is a circular waiting pattern
for example if you can ensure that you will always lock currencyLock
before you lock inventoryLock
and never attempt to lock currencyLock
when you already have inventoryLock
you will be fine
Upvotes: 3
Reputation: 44124
Just after posting this question I came up with a simple solution myself: Just make sure all the code acquires the locks in the same order. That way there can never be two thread both holding one of them.
If there is no natural order, alphabetical would suffice and be easy to remember.
Upvotes: 0