В каком состоянии находится поток при Deadlock
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Состояние потока при 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:
- Захватывает монитор объекта
acc1 - Пытается захватить монитор
acc2 - Переходит в состояние BLOCKED, ждёт освобождения
acc2
- Захватывает монитор объекта
-
Поток 2:
- Захватывает монитор
acc2 - Пытается захватить монитор
acc1 - Переходит в состояние BLOCKED, ждёт освобождения
acc1
- Захватывает монитор
-
Результат:
- Оба потока в 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, пытаясь захватить монитор. Они полностью зависают и не могут продолжить выполнение. Это опасное состояние, требующее правильного проектирования синхронизации.