Ответ
Классический deadlock возникает, когда два или более потока блокируют разные ресурсы и каждый ждет освобождения ресурса, захваченного другим. Гарантированный deadlock можно создать, нарушив принцип упорядочивания блокировок и добавив задержку для синхронизации состояния потоков.
Пример кода, моделирующего deadlock:
public class GuaranteedDeadlock {
private static final Object LockA = new Object();
private static final Object LockB = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (LockA) { // 1. Поток 1 захватывает LockA
System.out.println("Thread 1: Holding Lock A...");
try {
Thread.sleep(50); // Задержка для гарантии, что оба потока захватят свои первые блокировки
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for Lock B...");
synchronized (LockB) { // 3. Поток 1 пытается захватить LockB (но он у Thread 2) -> БЛОКИРОВКА
System.out.println("Thread 1: Acquired both locks!"); // Эта строка никогда не выполнится
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (LockB) { // 2. Поток 2 захватывает LockB
System.out.println("Thread 2: Holding Lock B...");
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for Lock A...");
synchronized (LockA) { // 4. Поток 2 пытается захватить LockA (но он у Thread 1) -> БЛОКИРОВКА
System.out.println("Thread 2: Acquired both locks!"); // Эта строка никогда не выполнится
}
}
});
thread1.start();
thread2.start();
// Оба потока теперь заблокированы навсегда.
}
}
Почему deadlock гарантирован:
- Разный порядок блокировок: Thread 1 берет
LockA, затемLockB. Thread 2 беретLockB, затемLockA. - Синхронизация через
sleep(): Задержка дает время каждому потоку захватить свой первый монитор до того, как они попытаются захватить второй. - Циклическое ожидание: Каждый поток удерживает ресурс, нужный другому, и ждет, создавая неразрешимую циклическую зависимость.
Для обнаружения deadlock во время выполнения можно использовать jstack или JMX (ThreadMXBean.findDeadlockedThreads()).
Ответ 18+ 🔞
Да ты посмотри на эту красоту, классический дедлок, ёпта! Это ж как в жизни: два мудака схватились за свои ресурсы и оба ждут, пока другой отпустит, а сами ни хуя не делают. Замкнутый круг, блядь, вечный!
Вот смотри, как это гарантированно устроить, прям как в лабораторных условиях, сука.
Код, который точно всех положит:
public class GuaranteedDeadlock {
private static final Object LockA = new Object();
private static final Object LockB = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (LockA) { // 1. Первый поток хватает LockA
System.out.println("Thread 1: Holding Lock A...");
try {
Thread.sleep(50); // Спим, чтобы второй успел схватить свой замок. Подлянка, блядь!
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for Lock B...");
synchronized (LockB) { // 3. А LockB-то уже занят! И тут наш герой замирает навеки.
System.out.println("Thread 1: Acquired both locks!"); // Этой строки мы, блядь, не увидим.
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (LockB) { // 2. Второй, не долго думая, цапает LockB
System.out.println("Thread 2: Holding Lock B...");
try {
Thread.sleep(50); // Тоже спит, хитрая жопа.
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for Lock A...");
synchronized (LockA) { // 4. Тянется к LockA, а тот уже в цепких лапах первого! И второй тоже встал колом.
System.out.println("Thread 2: Acquired both locks!"); // И этой — нихуя.
}
}
});
thread1.start();
thread2.start();
// Всё, приехали. Два потока смотрят друг на друга, как дураки, и ждут до скончания времён.
}
}
А почему это железный дедлок, спросишь ты? Да элементарно, Ватсон!
- Порядок — всё, блядь! Один берёт A потом B, второй — B потом A. Полный разброд и шатание, хуй с горы! Нет единого правила, вот они и перепутались.
- Задержка — мать подлости. Эти
sleep(50)— это гениально, ёпта! Они дают каждому успеть схватить свой первый замок до того, как они полезут за чужим. Без них могло бы и пронести, а так — гарантия, пиздец. - Цикл ебаный. Получается порочный круг: первому нужен B, который у второго, а второму нужен A, который у первого. Вротберунчик! И выхода нет, терпения ебать ноль.
А потом сидишь, смотришь — программа висит. Чтобы найти этих засранцев, юзай jstack — он тебе покажет, кто на ком повис, или из кода через ThreadMXBean.findDeadlockedThreads() — тоже отличная штука, сразу всех видно, кто кого заблокировал.