Задать вопрос
@nemoCAP

Почему возникает deadlock?

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

public class SomeClass {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition1 = lock.newCondition();
    private final Condition condition2 = lock.newCondition();

    public void first() {
        lock.lock();
        try {
            System.out.println("first");
        } finally {
            condition1.signal();
            lock.unlock();
        }
    }

    public void second() {
        lock.lock();
        try {
            condition1.await();
            System.out.println("second");
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void third() {
        lock.lock();
        try {
            condition2.await();
            System.out.println("third");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}


если я правильно понимаю, поток захватывает лок, доходит до условия (condition.await) и отпускает лок, позволяя другому потоку захватить лок и, либо выполнить вывод в консоль и просигналить об этом (condition.signal), либо остановится на условии и отпустить лок.

ЗЫ. суть задачи - гарантированно получить упорядоченный вывод (first, second, third).
  • Вопрос задан
  • 58 просмотров
Подписаться 1 Простой 4 комментария
Решения вопроса 1
Vamp
@Vamp
У вас тут гонка, а не дедлок. Методы second и third не успевают встать в ожидание condition.

Если визуализировать пошагово:
  1. first - захватил блокировку объекта lock
  2. second - захватить lock не может, так как он уже захвачен, поэтому встаёт в ожидание
  3. third - захватить lock не может, так как он уже захвачен, поэтому встаёт в ожидание
  4. first - пишет в консоль "first"
  5. first - сигналит condition1
  6. first - релизит lock
  7. second - просыпается и захватывает lock
  8. second - встаёт в ожидание condition1, которое будет бесконечным, потому что condition1 за всё время триггерится однократно и этот триггер уже отработал на 5 шаге

Ваш код сможет успешно завершиться если подобрать нужный тайминг. Например, так:
var c = new SomeClass();
try (var t = Executors.newFixedThreadPool(3)) {
    t.submit(c::second);
    t.submit(c::third);
    Thread.sleep(100);
    t.submit(c::first);
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы