Случаются ли ложные пробуждения в Java на самом деле? - PullRequest
198 голосов
/ 26 июня 2009

Видя различные вопросы, связанные с блокировкой, и (почти) всегда находя термин «цикл из-за ложных пробуждений» 1 Интересно, кто-нибудь сталкивался с подобным пробуждением (предполагая, что подходящая аппаратная / программная среда для пример)

Я знаю, что термин «ложный» означает отсутствие очевидной причины, но каковы могут быть причины такого рода события?

( 1 Примечание: я не ставлю под сомнение практику зацикливания.)

Редактировать: Вспомогательный вопрос (для тех, кто любит примеры кода):

Если у меня есть следующая программа, и я ее запускаю:

public class Spurious {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition cond = lock.newCondition();
        lock.lock();
        try {
            try {
                cond.await();
                System.out.println("Spurious wakeup!");
            } catch (InterruptedException ex) {
                System.out.println("Just a regular interrupt.");
            }
        } finally {
            lock.unlock();
        }
    }
}

Что я могу сделать, чтобы внезапно разбудить этого await, не ожидая вечно случайного события?

Ответы [ 6 ]

195 голосов
/ 27 июня 2009

В Википедии статья о ложных пробуждениях имеет такой лакомый кусочек:

Функция pthread_cond_wait() в Linux реализована с использованием системного вызова futex. Каждый блокирующий системный вызов в Linux внезапно возвращается с EINTR, когда процесс получает сигнал. ... pthread_cond_wait() не может перезапустить ожидание, потому что оно может пропустить реальное пробуждение за то короткое время, которое было за пределами системного вызова futex. Этого условия гонки можно избежать только путем проверки вызывающим абонентом инварианта. Поэтому сигнал POSIX будет генерировать ложное пробуждение.

Сводка : если сигнализируется процесс Linux, каждый из ожидающих потоков будет наслаждаться приятным горячим ложным пробуждением .

Я покупаю это. Эту таблетку легче проглотить, чем часто приводимую смутную причину «это для эффективности».

21 голосов
/ 29 сентября 2010

У меня есть производственная система, которая демонстрирует такое поведение. Поток ожидает сигнала о том, что в очереди есть сообщение. В периоды занятости до 20% пробуждений являются ложными (то есть, когда они просыпаются, в очереди ничего нет). Эта тема является единственным потребителем сообщений. Он работает на 8-процессорной коробке Linux SLES-10 и построен на GCC 4.1.2. Сообщения приходят из внешнего источника и обрабатываются асинхронно, потому что возникают проблемы, если моя система не читает их достаточно быстро.

13 голосов
/ 02 августа 2014

Чтобы ответить на вопрос в названии - Да! это действительно происходит. Хотя в статье Вики много говорится о ложных пробуждениях, хорошее объяснение того же, с которым я столкнулся выглядит следующим образом -

Только подумайте об этом ... как и любой код, планировщик потоков может временно отключиться из-за чего-то ненормального, происходящего в базовом аппаратном / программном обеспечении. Конечно, следует позаботиться о том, чтобы это происходило как можно реже, но поскольку не существует такого понятия, как 100% надежное программное обеспечение, разумно предположить, что это может произойти, и позаботиться о постепенном восстановлении в случае, если планировщик обнаружит это (например, наблюдая пропущенные сердцебиения).

Теперь, как планировщик мог восстановиться, учитывая, что во время отключения он мог пропустить некоторые сигналы, предназначенные для уведомления ожидающих потоков? Если планировщик ничего не делает, упомянутые «неудачные» потоки будут просто зависать, ожидая вечно - чтобы избежать этого, планировщик просто отправит сигнал всем ожидающим потокам.

Это делает необходимым заключение «контракта» о том, что ожидающий поток может быть уведомлен без причины. Чтобы быть точным, была бы причина - отключение планировщика - но поскольку поток спроектирован (по уважительной причине), чтобы не обращать внимания на внутренние детали реализации планировщика, эту причину, вероятно, лучше представить как «ложную».

Я читал этот ответ из источника и нашел его достаточно разумным. Также прочитайте

Ложные пробуждения в Java и как их избежать .

PS: Выше ссылка на мой личный блог, в котором есть дополнительная информация о ложных пробуждениях.

9 голосов
/ 26 июня 2009

Кэмерон Пурди написал сообщение в блоге некоторое время назад о том, что его затронула ложная проблема с пробуждением. Так что да, это случается

Я предполагаю, что это в спецификации (как возможность) из-за ограничений некоторых платформ, на которых развернута Java? хотя я могу ошибаться!

8 голосов
/ 05 мая 2011

Просто чтобы добавить это. Да, это случилось, и я потратил три дня на поиск причины многопоточности на 24-ядерном компьютере (JDK 6). 4 из 10 казней пережили это без какого-либо паттерна. Такого никогда не было на 2 или 8 ядрах.

Изучил некоторые онлайн-материалы, и это не проблема Java, а общее редкое, но ожидаемое поведение.

0 голосов
/ 03 июля 2018

https://stackoverflow.com/a/1461956/14731 содержит отличное объяснение того, почему вы должны защититься от ложных пробуждений, даже если базовая операционная система не запускает их. Интересно отметить, что это объяснение применимо ко многим языкам программирования, включая Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...