← Назад к вопросам
В каких случаях возникает deadlock в многопоточности
1.8 Middle🔥 151 комментариев
#Многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В каких случаях возникает deadlock в многопоточности
Deadlock (взаимная блокировка) — это ситуация, когда две или более потока остаются заблокированы навечно, ожидая друг друга. Это одна из самых опасных проблем в многопоточном программировании.
Условия возникновения Deadlock (четыре условия Кофмана)
Deadlock возникает только при одновременном выполнении всех четырёх условий:
- Mutual Exclusion (Взаимное исключение) — ресурс может быть занят только одним потоком
- Hold and Wait (Занимай и жди) — поток может удерживать ресурс и одновременно ждать другого
- No Preemption (Отсутствие вытеснения) — ресурс нельзя отобрать у потока насильно
- Circular Wait (Циклическое ожидание) — существует цикл потоков, каждый из которых ждёт ресурс, занимаемый следующим
Классический пример Deadlock
public class DeadlockExample {
static class Account {
int id;
double balance;
Account(int id, double balance) {
this.id = id;
this.balance = balance;
}
}
static void transferMoney(Account from, Account to, double amount) {
synchronized (from) {
System.out.println(Thread.currentThread().getName() + " захватил " + from.id);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (to) {
System.out.println(Thread.currentThread().getName() + " захватил " + to.id);
from.balance -= amount;
to.balance += amount;
}
}
}
public static void main(String[] args) {
Account account1 = new Account(1, 1000);
Account account2 = new Account(2, 2000);
Thread t1 = new Thread(() -> transferMoney(account1, account2, 100));
Thread t2 = new Thread(() -> transferMoney(account2, account1, 200));
t1.start();
t2.start();
}
}
Другие примеры Deadlock
Пример 2: Несогласованный порядок блокировок
public class DeadlockWithObjects {
Object lock1 = new Object();
Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
System.out.println("Method 1");
}
}
}
public void method2() {
synchronized (lock2) {
synchronized (lock1) {
System.out.println("Method 2");
}
}
}
}
Способы избежать Deadlock
1. Всегда использовать один и тот же порядок блокировок:
static void transferMoneyFixed(Account from, Account to, double amount) {
Account first = from.id < to.id ? from : to;
Account second = from.id < to.id ? to : from;
synchronized (first) {
synchronized (second) {
from.balance -= amount;
to.balance += amount;
}
}
}
2. Использовать ReadWriteLock:
import java.util.concurrent.locks.*;
public class SafeAccount {
private ReadWriteLock lock = new ReentrantReadWriteLock();
private double balance;
public void transfer(double amount) {
lock.writeLock().lock();
try {
balance -= amount;
} finally {
lock.writeLock().unlock();
}
}
}
3. Установить timeout на блокировку:
import java.util.concurrent.locks.*;
ReentrantLock lock = new ReentrantLock();
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// Критическая секция
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Deadlock — одна из самых сложных проблем для отладки, поэтому лучше использовать проверенные паттерны синхронизации и high-level API.