← Назад к вопросам

В каком состоянии находится поток при Deadlock

1.8 Middle🔥 201 комментариев
#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Состояние потока при Deadlock

При возникновении deadlock потоки находятся в состоянии WAITING или BLOCKED. Расскажу подробно о том, что происходит при deadlock.

Жизненный цикл потока (Thread States)

В Java поток может находиться в одном из 6 состояний:

NEW → RUNNABLE → WAITING → TIMED_WAITING → (RUNNABLE) → TERMINATED
            ↓
         BLOCKED

При Deadlock потоки находятся в BLOCKED или WAITING

BLOCKED состояние: Поток пытается захватить монитор (synchronized блок/метод), но не может, так как другой поток его держит.

WAITING состояние: Поток вызвал Object.wait(), Thread.join() или LockSupport.park() и ждёт уведомления.

Классический пример Deadlock

public class DeadlockExample {
    static class Account {
        private int balance;
        private int id;
        
        public Account(int id, int balance) {
            this.id = id;
            this.balance = balance;
        }
        
        public synchronized void withdraw(int amount) {
            balance -= amount;
        }
        
        public synchronized void deposit(int amount) {
            balance += amount;
        }
    }
    
    static class TransferThread extends Thread {
        private Account from;
        private Account to;
        private int amount;
        
        public TransferThread(Account from, Account to, int amount) {
            this.from = from;
            this.to = to;
            this.amount = amount;
        }
        
        @Override
        public void run() {
            synchronized (from) {
                System.out.println(Thread.currentThread().getName() + " locked " + from.id);
                
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                
                synchronized (to) {
                    System.out.println(Thread.currentThread().getName() + " locked " + to.id);
                    from.withdraw(amount);
                    to.deposit(amount);
                }
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        Account acc1 = new Account(1, 1000);
        Account acc2 = new Account(2, 1000);
        
        // Thread-1 ждёт монитор acc2, который держит Thread-2
        // Thread-2 ждёт монитор acc1, который держит Thread-1
        // Deadlock!
        
        Thread t1 = new TransferThread(acc1, acc2, 100);
        Thread t2 = new TransferThread(acc2, acc1, 50);
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
    }
}

Что происходит в момент Deadlock

  1. Поток 1:

    • Захватывает монитор объекта acc1
    • Пытается захватить монитор acc2
    • Переходит в состояние BLOCKED, ждёт освобождения acc2
  2. Поток 2:

    • Захватывает монитор acc2
    • Пытается захватить монитор acc1
    • Переходит в состояние BLOCKED, ждёт освобождения acc1
  3. Результат:

    • Оба потока в BLOCKED состоянии
    • Никто не может прогрессировать
    • Приложение зависает (hang)

Проверка состояния через Thread Dump

jstack <pid>

Вывод покажет:

"Thread-1" #12 prio=5 os_prio=0 tid=0x000002 nid=0x456 
waiting to lock <0x00000123> (java.lang.Object)
at DeadlockExample$TransferThread.run(...)

"Thread-2" #13 prio=5 os_prio=0 tid=0x000003 nid=0x789
waiting to lock <0x00000456> (java.lang.Object)
at DeadlockExample$TransferThread.run(...)

Как определить Deadlock программно

import java.lang.management.*;

public class DeadlockDetector {
    public static void main(String[] args) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        long[] ids = bean.findDeadlockedThreads();
        
        if (ids != null && ids.length > 0) {
            System.out.println("Deadlock обнаружен!");
            ThreadInfo[] infos = bean.getThreadInfo(ids);
            for (ThreadInfo info : infos) {
                System.out.println(info);
            }
        }
    }
}

Как избежать Deadlock

1. Правило упорядочения (Ordering):

synchronized (acc1) {
    synchronized (acc2) {  // Всегда в одном порядке
        // safe
    }
}

2. Использовать ReentrantLock с timeout:

Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();

if (lock1.tryLock(1, TimeUnit.SECONDS)) {
    try {
        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
            try {
                // безопасный код
            } finally {
                lock2.unlock();
            }
        }
    } finally {
        lock1.unlock();
    }
}

3. Минимизировать время блокировки:

synchronized (this) {
    // только самое необходимое
}

Итого

При deadlock потоки находятся в состоянии BLOCKED, пытаясь захватить монитор. Они полностью зависают и не могут продолжить выполнение. Это опасное состояние, требующее правильного проектирования синхронизации.