Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Отслеживание Deadlock в Java
Что такое Deadlock
Deadlock (взаимная блокировка) - это ситуация, когда два или более потока ждут друг друга и оба не могут продолжить выполнение. Это происходит, когда:
- Поток A владеет монитором 1 и ждет монитора 2
- Поток B владеет монитором 2 и ждет монитора 1
Отслеживание deadlock критично для диагностики и решения проблем с многопоточностью.
1. Метод 1: ThreadMXBean и Management API
Это самый программный способ обнаружения deadlock при выполнении:
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
public class DeadlockDetector {
public static void detectDeadlock() {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] deadlockedThreads = bean.findDeadlockedThreads();
if (deadlockedThreads != null && deadlockedThreads.length > 0) {
System.out.println("Deadlock detected!");
ThreadInfo[] infos = bean.getThreadInfo(deadlockedThreads);
for (ThreadInfo info : infos) {
System.out.println("Thread: " + info.getThreadName());
System.out.println("State: " + info.getThreadState());
}
}
}
public static void main(String[] args) throws InterruptedException {
while (true) {
detectDeadlock();
Thread.sleep(5000);
}
}
}
2. Метод 2: Полный мониторинг потоков
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.lang.management.ThreadInfo;
public class ThreadDeadlockMonitor {
public static void printAllThreadInfo() {
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] allThreadIds = bean.getAllThreadIds();
ThreadInfo[] infos = bean.getThreadInfo(allThreadIds, true, true);
for (ThreadInfo info : infos) {
if (info == null) continue;
System.out.println("Thread: " + info.getThreadName());
System.out.println("State: " + info.getThreadState());
System.out.println("Blocked count: " + info.getBlockedCount());
}
}
}
3. Метод 3: Демонстрация Deadlock
public class DeadlockExample {
static class Account {
private int balance = 1000;
synchronized void withdraw(int amount) {
balance -= amount;
}
}
public static void main(String[] args) throws InterruptedException {
Account account1 = new Account();
Account account2 = new Account();
Thread thread1 = new Thread(() -> {
synchronized (account1) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (account2) {
account1.withdraw(1);
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (account2) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (account1) {
account2.withdraw(1);
}
}
});
thread1.start();
thread2.start();
}
}
4. Метод 4: jstack - Внешний инструмент
jps
jstack 12345
jstack 12345 > thread_dump.txt
grep -A 5 "deadlock" thread_dump.txt
5. Метод 5: jconsole
jconsole
В интерфейсе:
- Выбрать процесс Java
- Перейти на вкладку Threads
- Нажать Detect Deadlock
6. Метод 6: VisualVM
jvisualvm
Интерфейс предоставляет:
- Real-time thread состояния
- Визуализацию deadlock
- Анализ памяти
- Профилирование CPU
7. Метод 7: Логирование с timeout
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class SmartLock {
private ReentrantLock lock = new ReentrantLock();
private String name;
SmartLock(String name) {
this.name = name;
}
void lockWithTimeout(long timeoutMs) throws InterruptedException {
System.out.println(Thread.currentThread().getName() +
" trying to lock " + name);
boolean acquired = lock.tryLock(timeoutMs, TimeUnit.MILLISECONDS);
if (!acquired) {
System.out.println("TIMEOUT! Could not acquire " + name);
throw new InterruptedException("Lock acquisition timeout");
}
}
}
8. Лучшие практики для предотвращения Deadlock
// Плохо: Deadlock вероятен
public void transfer(Account from, Account to) {
synchronized (from) {
synchronized (to) {
// May cause deadlock
}
}
}
// Хорошо: Всегда одинаковый порядок
public void transfer(Account from, Account to) {
Account first = from.getId() < to.getId() ? from : to;
Account second = from.getId() < to.getId() ? to : from;
synchronized (first) {
synchronized (second) {
// Deadlock невозможен
}
}
}
// Лучше: Используй timeout
private final ReentrantLock lock = new ReentrantLock();
public void operation() throws InterruptedException {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// операция
} finally {
lock.unlock();
}
} else {
throw new TimeoutException("Failed to acquire lock");
}
}
Заключение
Отслеживание deadlock - это критический аспект отладки многопоточных приложений. Основные методы:
- ThreadMXBean - программный анализ
- jstack - command-line снимок потоков
- jconsole/VisualVM - визуальный анализ
- Логирование с timeout - превентивная отладка
- Правильное управление блокировками - лучшая защита
Использование timeout и consistentного порядка захвата блокировок предотвращает deadlock эффективнее, чем его отслеживание.