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

Будет ли выброшен Exception при Deadlock?

3.0 Senior🔥 151 комментариев
#Многопоточность

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

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

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

Будет ли выброшен Exception при Deadlock?

Ответ неоднозначен и зависит от контекста: где происходит deadlock (на уровне БД, OS, или JVM) и как настроена система обработки ошибок.

На уровне базы данных

ДА, будет Exception — база данных ВЫЯВЛЯЕТ deadlock и генерирует ошибку для одной из транзакций.

При использовании JDBC или ORM (Hibernate, JPA), эта ошибка преобразуется в исключение:

public void transferMoney(Long accountA, Long accountB, BigDecimal amount) {
    try {
        // Транзакция A: читает accountA, затем accountB
        Account from = accountRepository.findById(accountA);
        Account to = accountRepository.findById(accountB);
        from.balance -= amount;
        to.balance += amount;
        accountRepository.save(from);
        accountRepository.save(to);
    } catch (DataAccessException e) {
        // Если произойдёт deadlock с другой транзакцией:
        // Будет выброшен DeadlockLoserDataAccessException
        if (e.getRootCause() instanceof java.sql.SQLException) {
            java.sql.SQLException sqlException = (java.sql.SQLException) e.getRootCause();
            if (sqlException.getErrorCode() == 1213) {  // MySQL deadlock code
                System.out.println("Deadlock detected!");
                // Можем попробовать повторить операцию
            }
        }
        throw e;
    }
}

Конкретные исключения по СУБД

PostgreSQL:

// Выбросит SQLException с кодом ошибки "40P01"
try {
    // Операция в транзакции
} catch (SQLException e) {
    if ("40P01".equals(e.getSQLState())) {
        System.out.println("PostgreSQL detected deadlock");
    }
}

MySQL:

// Выбросит SQLException с кодом ошибки 1213
try {
    // Операция в транзакции
} catch (SQLException e) {
    if (e.getErrorCode() == 1213) {
        System.out.println("MySQL detected deadlock");
    }
}

Oracle:

// Выбросит SQLException с кодом ошибки ORA-00060
try {
    // Операция в транзакции
} catch (SQLException e) {
    if (e.getErrorCode() == 60) {
        System.out.println("Oracle detected deadlock");
    }
}

Через Hibernate/JPA

Hibernate преобразует ошибки БД в более удобные исключения:

public class TransferService {
    @Autowired
    private AccountRepository accountRepository;
    
    @Transactional
    public void transferWithRetry(Long fromId, Long toId, BigDecimal amount) {
        int maxRetries = 3;
        int retryCount = 0;
        
        while (retryCount < maxRetries) {
            try {
                Account from = accountRepository.findById(fromId).orElseThrow();
                Account to = accountRepository.findById(toId).orElseThrow();
                from.setBalance(from.getBalance().subtract(amount));
                to.setBalance(to.getBalance().add(amount));
                accountRepository.saveAll(List.of(from, to));
                return;
            } catch (DataIntegrityViolationException e) {
                // Может быть выброшен при deadlock
                retryCount++;
                if (retryCount >= maxRetries) {
                    throw new RuntimeException("Failed after " + maxRetries + " retries", e);
                }
                try {
                    Thread.sleep(100 * retryCount);  // Exponential backoff
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

На уровне OS (Thread Deadlock)

Если deadlock произойдёт между потоками Java (например, взаимные блокировки synchronized блоков), Exception может быть НЕ выброшен:

// Пример thread deadlock
public class ThreadDeadlockExample {
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    
    public void method1() {
        synchronized (lock1) {
            System.out.println("Thread 1: Got lock1");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            
            synchronized (lock2) {  // Ждёт lock2, но её держит Thread 2
                System.out.println("Thread 1: Got lock2");
            }
        }
    }
    
    public void method2() {
        synchronized (lock2) {
            System.out.println("Thread 2: Got lock2");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            
            synchronized (lock1) {  // Ждёт lock1, но её держит Thread 1
                System.out.println("Thread 2: Got lock1");
            }
        }
    }
    
    public static void main(String[] args) {
        ThreadDeadlockExample example = new ThreadDeadlockExample();
        
        new Thread(example::method1, "Thread-1").start();
        new Thread(example::method2, "Thread-2").start();
        
        // Программа просто зависнет! Exception не будет выброшен
        // Только Thread.dump покажет deadlock
    }
}

В этом случае Exception НЕ выбросится, программа просто зависнет.

Как обнаружить thread deadlock

public void detectDeadlock() {
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
    
    if (deadlockedThreads != null && deadlockedThreads.length > 0) {
        System.out.println("Deadlock detected! Affected threads: "
            + Arrays.toString(deadlockedThreads));
        
        ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(deadlockedThreads);
        for (ThreadInfo threadInfo : threadInfos) {
            System.out.println(threadInfo.getThreadName() + " is waiting for "
                + threadInfo.getLockName());
        }
    }
}

Итоговая таблица

Тип DeadlockException выбросится?Как обработать
Database DeadlockДА (SQLException)Catch & retry, или логирование
Thread DeadlockНЕТThread dump, mониторинг, проектирование
Timeout DeadlockДА (TimeoutException)Configurate timeout, retry

Рекомендации

  1. Избегайте deadlock-ов через правильный порядок блокировок
  2. Всегда обрабатывайте исключения БД в транзакциях
  3. Используйте retry logic с exponential backoff
  4. Мониторьте deadlock-и на production
  5. Для thread deadlock-ов проектируйте код без циклических зависимостей
  6. Используйте timeout-ы при работе с блокировками

Вывод: deadlock на уровне БД выбросит Exception, но deadlock между потоками в Java может просто заморозить приложение без исключения.