Всякий раз, когда у вас есть несколько замков A, B и C, у вас может быть тупик, если вы не гарантируете, что ваш код пытается приобрести указанные блокировки в том же заказе.
final Lock A = new ReentrantLock();
final Lock B = new ReentrantLock();
final Lock C = new ReentrantLock();
A, b, c или c, b, a или a, c, b - это не имеет значения, пока порядок является последовательным.
Проблема возникает, когда у вас есть один путь кода, попробуйте: A, B, C, а другой пытается для C, B, A.
Как вы, вероятно, можете догадаться, так как оба удерживаются A и C, один из них получит B, а затем оба будут тупиться. (AKA у вас есть цикл на графике блокировки ресурсов)
Формально говорящий тупик может возникнуть только если Все следующие условия удерживаются:
- Без предположения: система не будет свободным ресурсами после распределения; Они могут быть освобождены только процессом удержания.
- Круговое ожидание: обсуждается выше.
- Взаимное исключение: только один процесс может использовать ресурс в любой момент времени.
- Удержание ресурсов: в настоящее время процесс имеет как минимум один ресурс и запрашивает/ожидает дополнительных ресурсов, которые удерживаются другим процессом.
Лучшее решение - убедиться, что порядок является согласованным или блокировал на более высоком (одиночном) уровне. Другой вариант - использовать записную библиотеку, которая будет тайм -аутом при попытке блокировать (или использовать условия и написать свою собственную обертку, которая делает это). Но этот подход не для слабонервных. Некоторая реализация этого будет ждать случайное количество времени и повторить попытку, но это может быть очень неэффективным, поскольку количество замков увеличивается.
Ресурсы:
- Вот практическая статья об анализе тупика в Яве, которую вам может быть интересно:http://www.journaldev.com/1058/java-deadlock-example-and-how-to-analyze-deadlock-situcation
- Вы также можете использовать инструменты с открытым исходным кодом, такие как JCarder, чтобы найти тупик:http://www.jcarder.org/ Что для программ с большими дампами может быть проще, а затем попытаться запустить файлы дампы Grok.
PS Я на самом деле не читал большую часть вашего кода, так как его плохо отформатировано и не является минимальным примером (т.е. слишком условно для наших целей здесь). Но этот совет должен ответить вам на вопрос с теоретической точки зрения.