Страницы

Поиск по вопросам

четверг, 2 мая 2019 г.

Не понятна логика возникновения DeadLock

public void transferMoney(Account fromAccount, Account toAccount, Amount amount) throws InsufficientFundsException { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } }
Описание: Если со счета A на счет B перевести x денег, а со счета B на счет A – y, то при неудачном стечении обстоятельств, транзакция 1 займет монитор счета A, транзакция 2 займет монитор счета B. Результат – взаимная блокировка.
Я никак не могу понять: Как же второй трэд доберётся до второго synchronized, если первый synchronized уже был заблокирован первым трэдом? Пересмотрел уже кучу лекций и перечитал про synchronized.


Ответ

Он не будет заблокирован. synchronized воспользуется intrinsic lock того объекта, который будет указан в самом synchronized, поэтому два потока могут войти во внешний synchronized при том условии, что они используют два разных объекта: де-факто, synchronized(lockObject) - это гарантия использования объекта только одним потоком, но не гарантия исполнения кода максимум одним потоком в любой момент времени. Для достижения дедлока в этом случае достаточно, чтобы ни один из потоков не смог войти во внутренний synchronized - и это условие выполняется, если используются те же два аккаунта, но в противоположных потоках:
Thread 1 | Thread 2 -------------------|------------------- обычное состояние | обычное состояние взял лок объекта А | взял лок объекта Б ждет лок объекта Б | ждет лок объекта А
В этом случае прогресс невозможен, потому что для освобождения ресурса требуется прогресс любого из потоков, а это возможно только в случае освобождения ресурса.

Комментариев нет:

Отправить комментарий