← Назад к вопросам
Как можно сделать Deadlock двух потоков?
1.7 Middle🔥 201 комментариев
#Многопоточность и асинхронность
Комментарии (1)
🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как создать Deadlock двух потоков
Deadlock (взаимная блокировка) возникает, когда два или более потоков **взаимно ожидают** освобождения ресурсов, захваченных другими потоками, создавая бесконечное ожидание. Это классическая проблема многопоточного программирования.
Классический пример Deadlock
Для создания взаимной блокировки необходимо выполнение четырех условий Коффмана:
- Взаимное исключение - ресурсы неделимы
- Удержание и ожидание - поток удерживает ресурс и ждет другой
- Отсутствие вытеснения - ресурсы нельзя отобрать принудительно
- Циклическое ожидание - образуется цикл зависимостей
Вот практический пример на 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
Для обнаружения взаимных блокировок можно использовать:
- Android Studio Profiler - анализ потоков
- StrictMode - обнаружение проблем в UI потоке
- Логирование с идентификаторами потоков
- Кастомные детекторы на основе мониторинга
Понимание механизмов создания deadlock важно не для их использования в production-коде, а для осознанного предотвращения подобных ситуаций и написания надежного многопоточного кода.