Вот пример такого лока, код, который, казалось бы, работает верно, но может привести к дедлоку, если from и to поменяются местами при следющем вызове.
public void transerMoney(Account from, Account to, Dollar amount) { synchronized (from) { synchronized (to) { if (from.getBalance().compareTo(amount) < 0) { throw new InsufficientFundsException(); } from.debit(amount); to.credit(amout); } } }как можно переписать этот код ? ну например можно определять хеш объекта, чтоб установить порядок лока.
public void transerMoney(Account from, Account to, Dollar amount) { int fromHash = System.identityHashCode(from); int toHash = System.identityHashCode(to); if (fromHash < toHash) { synchronized (from) { synchronized (to) { transfer(); } } } else if (fromHash > toHash){ synchronized (to) { synchronized (from) { transfer(); } } } }Можно также использовать интерфейс Lock и явно создать ReentrantLock
public void transerMoney(Account from, Account to, Dollar amount) { if (from.lock.tryLock()) { try { if (to.lock.tryLock()) { try { transfer(); } finally { to.lock.unlock(); } } } finally { from.lock.unlock(); } } }
tryLock возьмет лок или сразу же вернет false, если он не может взять lock. В коде выше например можно добавить проверку, которая определяет удалось ли нам осуществить операцию, при необходимости повторить её снова.
Комментариев нет:
Отправить комментарий