Отвечая на вопрос ОП
Что я могу сделать, чтобы внезапно разбудить это ожидание, не ожидая вечно случайного события?
, Нет какого - либо паразитных пробуждения могло проснуться этой ожидающая нить!
Независимо от того, могут ли ложные пробуждения происходить или не происходить на конкретной платформе, в случае с фрагментом 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 имеет ложные пробуждения?» ,