Борьба с взаимными блокировками в Java

В жизни обычного программиста редко возникает возможность писать что-то действительно крутое и интересное. Большая часть нашей работы связана лишь со скрупулёзностью, усидчивостью, вниманием и монотонностью. Лишь на собеседованиях можно применить что-либо действительно интересное. Или странное. В этой статье я опишу способ решения проблемы смертельных блокировок (deadlock-ов), который может вам пригодиться при прохождении некоторых собеседований.Предположим, что у нас есть система, работающая со счетами пользователей. Счета пользователей представлены классом Account:

На первый взгляд может показаться, что всё в порядке. Но на самом деле в этом коде спрятана взаимная блокировка. Если вызвать transfer на первом счёте, а затем на втором, то может произойти так, что:

  1. Берётся блокировка this на методе synchronized у счёта 1.
  2. Происходит переключение потоков.
  3. Берётся блокировка this на методе synchronized у счёта 2.
  4. Происходит переключение потоков.
  5. Поток, уже имеющий блокировку на счёте 1, пытается взять блокировку на счёте 2 в синхронизированном блоке, но блокировка this у счёта 2 уже занята, поэтому поток останавливается до тех пор, пока блокировка счёта 2 не освободиться.
  6. Поток, уже имеющий блокировку на счёте 2, пытается взять блокировку на счёте 1 в синхронизированном блоке, но блокировка this у счёта 1 уже занята, поэтому поток останавливается до тех пор, пока блокировка счёта 1 не освободится.
  7. Оба потока ждут освобождения блокировок друг друга, чего никогда не произойдёт.

Как избавиться от подобного? В данном случае можно обратить внимание на идентификатор счёта id. Понятное дело, что каждый счёт имеет уникальный идентификатор. Чтобы избежать deadlock-ов мы можем всегда брать блокировки строго в порядке сортировки их идентификаторов, то есть сначала меньший, а затем больший, чем решим проблему взаимных блокировок для этого случая:

Если же окажется так, что объекты на которых нужно взять блокировку, не имеют уникальных полей, по которым можно определять меньший и больший объект, то можно ввести подобные поля синтетически.

Один комментарий к “Борьба с взаимными блокировками в Java”

  1. .Предположим -> После точки нет пробела
    Чтобы избежать deadlock-ов мы можем (Запятая?)
    что объекты на которых нужно взять блокировку -> запятая после «объекты»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *