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

Как можно сделать Deadlock двух потоков?

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

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

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

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

Как создать Deadlock двух потоков

Deadlock (взаимная блокировка) возникает, когда два или более потоков **взаимно ожидают** освобождения ресурсов, захваченных другими потоками, создавая бесконечное ожидание. Это классическая проблема многопоточного программирования.

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

Для создания взаимной блокировки необходимо выполнение четырех условий Коффмана:

  1. Взаимное исключение - ресурсы неделимы
  2. Удержание и ожидание - поток удерживает ресурс и ждет другой
  3. Отсутствие вытеснения - ресурсы нельзя отобрать принудительно
  4. Циклическое ожидание - образуется цикл зависимостей

Вот практический пример на Java/Kotlin, демонстрирующий создание deadlock:

object DeadlockDemo {
    private val lockA = Object()
    private val lockB = Object()
    
    fun createDeadlock() {
        val thread1 = Thread {
            synchronized(lockA) {
                println("Поток 1: Захватил lockA")
                
                // Имитация работы, чтобы увеличить вероятность deadlock
                Thread.sleep(100)
                
                synchronized(lockB) {
                    println("Поток 1: Захватил lockB")
                }
            }
        }
        
        val thread2 = Thread {
            synchronized(lockB) {
                println("Поток 2: Захватил lockB")
                
                // Имитация работы
                Thread.sleep(100)
                
                synchronized(lockA) {
                    println("Поток 2: Захватил lockA")
                }
            }
        }
        
        thread1.start()
        thread2.start()
        
        thread1.join()
        thread2.join()
    }
}

// Использование
fun main() {
    DeadlockDemo.createDeadlock()
}

Более сложный пример с использованием ReentrantLock

import java.util.concurrent.locks.ReentrantLock;

public class AdvancedDeadlock {
    private final ReentrantLock lock1 = new ReentrantLock();
    private final ReentrantLock lock2 = new ReentrantLock();
    
    public void execute() {
        Thread t1 = new Thread(() -> {
            lock1.lock();
            System.out.println("Thread 1: Locked resource 1");
            
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            lock2.lock(); // Ждет lock2, который удерживается Thread 2
            System.out.println("Thread 1: Locked resource 2");
            
            lock2.unlock();
            lock1.unlock();
        });
        
        Thread t2 = new Thread(() -> {
            lock2.lock();
            System.out.println("Thread 2: Locked resource 2");
            
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            lock1.lock(); // Ждет lock1, который удерживается Thread 1
            System.out.println("Thread 2: Locked resource 1");
            
            lock1.unlock();
            lock2.unlock();
        });
        
        t1.start();
        t2.start();
    }
}

Распространенные сценарии Deadlock в Android

В Android разработке deadlock может возникать в различных ситуациях:

1. Взаимодействие UI-thread и фоновых потоков

// Потенциальный deadlock при неправильной синхронизации
class DeadlockActivity : AppCompatActivity() {
    private val mainHandler = Handler(Looper.getMainLooper())
    private val backgroundLock = Object()
    
    fun problematicMethod() {
        Thread {
            synchronized(backgroundLock) {
                // Попытка обновить UI из фонового потока
                mainHandler.post {
                    synchronized(backgroundLock) { // Deadlock!
                        updateUI()
                    }
                }
            }
        }.start()
    }
}

2. Взаимные вызовы между synchronized методами

class AccountManager {
    private val accountLock = Any()
    private val transactionLock = Any()
    
    @Synchronized
    fun transferFunds() {
        synchronized(transactionLock) {
            validateTransaction() // Может вызвать validateAccount()
        }
    }
    
    @Synchronized  
    fun validateTransaction() {
        synchronized(accountLock) {
            // Валидация счета
        }
    }
}

Методы предотвращения Deadlock

Хотя знание создания deadlock важно для собеседования, на практике его нужно избегать:

  • Упорядочивание блокировок - всегда захватывать ресурсы в одинаковом порядке
  • Использование tryLock() с таймаутом для ReentrantLock
  • Избегание вложенных синхронизаций
  • Использование атомарных операций и thread-safe коллекций
  • Применение детекторов deadlock в production коде

Диагностика Deadlock в Android

Для обнаружения взаимных блокировок можно использовать:

  1. Android Studio Profiler - анализ потоков
  2. StrictMode - обнаружение проблем в UI потоке
  3. Логирование с идентификаторами потоков
  4. Кастомные детекторы на основе мониторинга

Понимание механизмов создания deadlock важно не для их использования в production-коде, а для осознанного предотвращения подобных ситуаций и написания надежного многопоточного кода.