«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Почему один поток всегда повторно получает блокировку объекта после notify() или notifyAll()?

Почему один поток всегда повторно получает блокировку объекта после notify() или notifyAll()?

Опубликовано 16 ноября 2024 г.
Просматривать:458

Why Does One Thread Always Reacquire the Object Lock After notify() or notifyAll()?

Тонкое различие между notify() и notifyAll()

Хотя основное различие между notify() и notifyAll() заключается в количество ожидающих потоков, которые они пробуждают (один против всех), возникает еще один вопрос:

Почему один поток всегда повторно получает блокировку объекта?

В общем В этом случае и notify(), и notifyAll() не указывают, какой ожидающий поток будет выбран для повторного получения блокировки. Планировщик JVM или системных потоков делает этот выбор, который может быть недетерминированным.

Необходимость notifyAll()

Однако использование notify() в определенных сценариях может привести к тупику, как показано в следующем примере:

Класс Producer/Consumer с notify()

public class ProducerConsumer {

    private final int MAX_SIZE = 1;  // Buffer size

    private List buf = new ArrayList();

    public synchronized void put(Object o) {
        while (buf.size() == MAX_SIZE) {
            wait();
        }
        buf.add(o);
        notify();
    }

    public synchronized Object get() {
        while (buf.size() == 0) {
            wait();
        }
        Object o = buf.remove(0);
        notify();
        return o;
    }
}

Сценарий взаимоблокировки:

  1. Производитель P1 помещает объект в буфер.
  2. Производитель P2 и P3 пытаются поместить объекты, но заблокировано, поскольку буфер заполнен.
  3. Потребитель C1 пытается получить объект из буфера.
  4. C1 выполняется и получает объект, а затем уведомляет ожидающий поток.
  5. P2 или C2 могут быть разбужены уведомлением, но они оба заблокированы при попытке повторного получения блокировки.
  6. C3 также блокируется при попытке получить блокировку.

Как В результате все три потока ожидают неопределенное время, что приводит к взаимоблокировке.

Решение: notifyAll()

Чтобы разрешить эту взаимоблокировку, необходимо использовать notifyAll() вместо notify() в коде производителя/потребителя. Это гарантирует пробуждение всех ожидающих потоков и предотвращение взаимоблокировок.

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

Для большинства сценариев notifyAll() является предпочтительным методом, поскольку он позволяет избежать потенциальных взаимоблокировок. Если конкретный сценарий требует пробуждения только одного конкретного ожидающего потока, то notify() можно использовать с осторожностью.

Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3