Отвечая на вопрос ОП
Что я могу сделать, чтобы внезапно разбудить это ожидание, не ожидая вечно случайного события?
, Нет какого - либо паразитных пробуждения могло проснуться этой ожидающая нить!
Независимо от того, могут ли ложные пробуждения происходить или не происходить на конкретной платформе, в случае с фрагментом OP это определенно невозможно дляCondition.await()
вернуться и увидеть строку «Ложные пробуждения!» в выходном потоке.
Если вы не используете очень экзотическую библиотеку классов Java
Это потому , что стандарт, OpenJDK «s ReentrantLock
метод» s newCondition()
возвращает AbstractQueuedSynchronizer
«S реализацию Condition
интерфейса, вложенная ConditionObject
(кстати, это единственная реализация Condition
интерфейса в этой библиотеке классов), а ConditionObject
» метода s await()
сам проверяет , имеет ли условие не удерживает, и никакое ложное пробуждение не может заставить этот метод ошибочно вернуться.
Кстати, вы можете проверить это сами, так как довольно легко эмулировать ложное пробуждение, когда AbstractQueuedSynchronizer
задействована основанная реализация.
AbstractQueuedSynchronizer
использует низкоуровневые LockSupport
«s park
и unpark
методов, а также, если вы вызываете LockSupport.unpark
на поток ожидает наCondition
это действие не может отличить от ложного пробуждения.
Немного рефакторинг фрагмента OP,
public class Spurious {
private static class AwaitingThread extends Thread {
@Override
public void run() {
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();
}
}
}
private static final int AMOUNT_OF_SPURIOUS_WAKEUPS = 10;
public static void main(String[] args) throws InterruptedException {
Thread awaitingThread = new AwaitingThread();
awaitingThread.start();
Thread.sleep(10000);
for(int i =0 ; i < AMOUNT_OF_SPURIOUS_WAKEUPS; i++)
LockSupport.unpark(awaitingThread);
Thread.sleep(10000);
if (awaitingThread.isAlive())
System.out.println("Even after " + AMOUNT_OF_SPURIOUS_WAKEUPS + " \"spurious wakeups\" the Condition is stil awaiting");
else
System.out.println("You are using very unusual implementation of java.util.concurrent.locks.Condition");
}
}
и независимо от того, как сильно непаркирующий (основной) поток будет пытаться разбудить ожидающий поток, Condition.await()
в этом случае метод никогда не вернется.
Ложные пробуждения о Condition
методах ожидания обсуждаются в javadoc Condition
интерфейса . Хотя это говорит о том,
при ожидании условия допускается ложное пробуждение
и это
рекомендуется, чтобы прикладные программисты всегда предполагали, что они могут произойти, и поэтому всегда ожидали в цикле.
но позже добавляет, что
Реализация свободна, чтобы удалить возможность ложных пробуждений
и AbstractQueuedSynchronizer
реализация Condition
интерфейса делает именно это - устраняет любую возможность ложных пробуждений .
Это, безусловно, справедливо и для других ConditionObject
ожидающих методов.
Итак, вывод таков:
мы всегда должны вызывать Condition.await
в цикле и проверять, не выполняется ли условие, но со стандартным OpenJDK библиотека классов Java никогда не может произойти . Если, опять же, вы не используете очень необычную библиотеку классов Java (которая должна быть очень необычной, потому что другие хорошо известные не-OpenJDK библиотеки классов Java, в настоящее время почти вымершие GNU Classpath и Apache Harmony , похоже, идентичны стандартной реализации Condition
интерфейса)
pthread_cond_wait()
реальный вопрос: «Почему pthread_cond_wait имеет ложные пробуждения?» ,