Приводит ли возникновение deadlock (взаимной блокировки) к выбрасыванию исключения (Exception) в Java?

Ответ

Нет, deadlock сам по себе не вызывает исключений. Это ситуация логической ошибки, при которой два или более потока бесконечно ожидают друг друга, освободив заблокированные ресурсы. JVM не рассматривает это как исключительную ситуацию (Exception), поэтому программа просто зависает (перестаёт прогрессировать).

Пример классического deadlock:

final Object lock1 = new Object();
final Object lock2 = new Object();

new Thread(() -> {
    synchronized (lock1) {          // Поток 1 захватывает lock1
        Thread.sleep(100);
        synchronized (lock2) { }   // Ждёт, пока освободится lock2
    }
}).start();

new Thread(() -> {
    synchronized (lock2) {          // Поток 2 захватывает lock2
        Thread.sleep(100);
        synchronized (lock1) { }   // Ждёт, пока освободится lock1 -> DEADLOCK
    }
}).start();

Как обнаружить deadlock? Поскольку исключение не выбрасывается, для диагностики используются внешние средства:

  • Инструменты JDK: Утилита jstack <PID> выведет дамп потоков и укажет на обнаруженные взаимные блокировки.
  • Мониторинг через JMX.
  • Профилировщики и IDE.

Профилактика: Избегайте deadlock, устанавливая фиксированный порядок захвата блокировок или используя более высокоуровневые средства синхронизации из java.util.concurrent.

Ответ 18+ 🔞

А, слушай, вот тебе классика жанра, прям как в том анекдоте про двух упырей, которые друг другу в дверях уступить не могут. Deadlock, ёпта, он исключений не кидает, это ж не какая-нибудь NullPointerException, которую можно на коленке поймать. Это тихий, ебучий конец света для твоей программы. Просто встал как вкопанный и всё — терпения ноль ебать, а он молчит.

Представь двух мудаков-потоков. Один, сука, схватил замок lock1 и сидит, довольный. Второй, недолго думая, цап lock2. А дальше начинается цирк.

Первый говорит: «Отпусти lock2, я тогда свой lock1 отпущу». Второй, блядь, в ответ: «Да ты что, охренел? Сначала ты свой lock1 отпусти, тогда я про lock2 подумаю!»

И вот они сидят, уставились друг на друга, как два идиота, и ждут. Ждут до второго пришествия. Программа — труп. Ни тебе прогресса, ни тебе ошибки. Просто тишина, блядь. Удивление пиздец.

final Object lock1 = new Object();
final Object lock2 = new Object();

new Thread(() -> {
    synchronized (lock1) {          // Поток 1: Захватил lock1. Мой!
        Thread.sleep(100);
        synchronized (lock2) { }   // А теперь хочу lock2. Отдавай, падла!
    }
}).start();

new Thread(() -> {
    synchronized (lock2) {          // Поток 2: А я lock2 взял. Не отдам!
        Thread.sleep(100);
        synchronized (lock1) { }   // О, а lock1 мне нужен. Давай сюда! -> DEADLOCK, ебанашка
    }
}).start();

И что делать? В логах нихуя не светится. Надо лезть со специнструментами, как сапёр на минное поле. Запускаешь jstack, а он тебе вываливает эту позорную картину: «Смотри, дебилы, вот они, ваши потоки, друг друга за горло держат».

Чтобы такого пиздеца не было, надо или порядок установить железный — все замки всегда в одной последовательности хватать, или вообще на java.util.concurrent перелезть, там умные штуки есть, которые от таких детсадовских драк защищают. А то так и будешь потом глазами дампы читать, материться и думать: «Ну я и мудя это написал».