Рассматривая различные вопросы, связанные с блокировкой, и (почти) всегда находя термин «цикл из-за ложных пробуждений» 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
, не ожидая навсегда случайного события?
java
multithreading
locking
spurious-wakeup
akarnokd
источник
источник
pthread_cond_wait()
реальный вопрос: «Почему pthread_cond_wait имеет ложные пробуждения?» ,Ответы:
В статье Википедии о ложных пробуждениях есть этот кусочек:
Описание : Если процесс Linux сигнализирует, его ожидающие потоки будут наслаждаться приятным горячим ложным пробуждением .
Я покупаю это. Эту таблетку легче проглотить, чем часто приводимую расплывчатую причину «это для эффективности».
источник
futex()
вызов возвращаетсяEINTR
, но это возвращаемое значение не поднимается до следующего уровня. Поэтому вызывающий pthread должен проверить наличие инварианта. Они говорят, что приpthread_cond_wait()
возврате вы должны снова проверить условие цикла (инвариант), потому что ожидание могло быть внезапно пробуждено. Получение сигнала во время системного вызова - одна из возможных причин, но не единственная.pthread
библиотека могла бы предоставить свой собственный инвариант и собственную логику проверки, чтобы устранить ложные пробуждения, вместо того, чтобы передавать эту ответственность пользователю. Это (предположительно) окажет заявленное влияние на производительность.У меня есть производственная система, которая демонстрирует это поведение. Поток ожидает сигнала о том, что в очереди есть сообщение. В периоды занятости до 20% пробуждений являются ложными (т.е. когда они просыпаются, в очереди ничего нет). Эта тема является единственным потребителем сообщений. Он работает на 8-процессорной коробке Linux SLES-10 и построен на GCC 4.1.2. Сообщения приходят из внешнего источника и обрабатываются асинхронно, потому что возникают проблемы, если моя система не читает их достаточно быстро.
источник
Ответить на вопрос в титуле - да! это действительно случается. Хотя статья Wiki упоминает много о ложных пробуждениях, хорошее объяснение того же, с чем я столкнулся, следующее:
Я читал этот ответ из источника и нашел его достаточно разумным. Также прочитайте
Ложные пробуждения в Java и как их избежать .
PS: Выше ссылка на мой личный блог, в котором есть дополнительная информация о ложных пробуждениях.
источник
Некоторое время назад Кэмерон Пурди написала в своем блоге сообщение о проблеме ложного пробуждения. Так что да, так бывает
Я предполагаю, что это в спецификации (как возможность) из-за ограничений некоторых платформ, на которых развернута Java? хотя я могу ошибаться!
источник
Просто чтобы добавить это. Да, это случилось, и я потратил три дня на поиск причины многопоточности на 24-ядерном компьютере (JDK 6). 4 из 10 казней пережили это без какого-либо паттерна. Это никогда не случалось на 2 или 8 ядер.
Изучил некоторые онлайн-материалы, и это не проблема Java, а общее редкое, но ожидаемое поведение.
источник
https://stackoverflow.com/a/1461956/14731 содержит отличное объяснение того, почему вам нужно защититься от ложных пробуждений, даже если базовая операционная система их не запускает. Интересно отметить, что это объяснение применимо ко многим языкам программирования, включая Java.
источник
Отвечая на вопрос ОП
, Нет какого - либо паразитных пробуждения могло проснуться этой ожидающая нить!
Независимо от того, могут ли ложные пробуждения происходить или не происходить на конкретной платформе, в случае с фрагментом OP это определенно невозможно для
Condition.await()
вернуться и увидеть строку «Ложные пробуждения!» в выходном потоке.Если вы не используете очень экзотическую библиотеку классов Java
Это потому , что стандарт, OpenJDK «s
ReentrantLock
метод» snewCondition()
возвращаетAbstractQueuedSynchronizer
«S реализациюCondition
интерфейса, вложеннаяConditionObject
(кстати, это единственная реализацияCondition
интерфейса в этой библиотеке классов), аConditionObject
» метода sawait()
сам проверяет , имеет ли условие не удерживает, и никакое ложное пробуждение не может заставить этот метод ошибочно вернуться.Кстати, вы можете проверить это сами, так как довольно легко эмулировать ложное пробуждение, когда
AbstractQueuedSynchronizer
задействована основанная реализация.AbstractQueuedSynchronizer
использует низкоуровневыеLockSupport
«spark
иunpark
методов, а также, если вы вызываетеLockSupport.unpark
на поток ожидает наCondition
это действие не может отличить от ложного пробуждения.Немного рефакторинг фрагмента OP,
и независимо от того, как сильно непаркирующий (основной) поток будет пытаться разбудить ожидающий поток,
Condition.await()
в этом случае метод никогда не вернется.Ложные пробуждения о
Condition
методах ожидания обсуждаются в javadocCondition
интерфейса . Хотя это говорит о том,и это
но позже добавляет, что
и
AbstractQueuedSynchronizer
реализацияCondition
интерфейса делает именно это - устраняет любую возможность ложных пробуждений .Это, безусловно, справедливо и для других
ConditionObject
ожидающих методов.Итак, вывод таков:
мы всегда должны вызывать
Condition.await
в цикле и проверять, не выполняется ли условие, но со стандартным OpenJDK библиотека классов Java никогда не может произойти . Если, опять же, вы не используете очень необычную библиотеку классов Java (которая должна быть очень необычной, потому что другие хорошо известные не-OpenJDK библиотеки классов Java, в настоящее время почти вымершие GNU Classpath и Apache Harmony , похоже, идентичны стандартной реализацииCondition
интерфейса)источник