Відповідаючи на питання ОП
Що я можу зробити, щоб розбудити це очікування неправдиво, не чекаючи вічно випадкової події?
, жоден хибний пробудження не міг розбудити цю очікувану нитку!
Незалежно від того , паразитні пробуджень може або не може статися на конкретній платформі, в разі ФП - х фрагмент коду це позитивно неможливо для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 цю дію не може відрізнити від помилкового пробудження.
Трохи переробляючи фрагмент ОП,
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методів очікування очікуються в інтерфейсі javadocCondition . Хоча це і говорить,
під час очікування стану, допускається хибне пробудження
і це
рекомендується, щоб програмісти програм завжди припускали, що вони можуть статися, і тому завжди чекайте в циклі.
але згодом це додає
Реалізація безкоштовна, щоб усунути можливість помилкових пробуджень
і AbstractQueuedSynchronizerреалізація Conditionінтерфейсу робить саме це - видаляє будь-яку можливість помилкових пробуджень .
Це, безумовно, справедливо для інших ConditionObjectочікуючих методів.
Отже, висновок такий:
ми завжди повинні зателефонувати Condition.awaitв цикл і перевірити, чи не виконується умова, але зі стандартними OpenJDK, бібліотекою класів Java ніколи не може відбутися . Якщо, знову ж, ви не використовуєте дуже незвичайну бібліотеку класів Java (що має бути дуже незвично, тому що інші відомі бібліотеки класів Java, які не є OpenJDK, на даний момент майже вимерлі Class Class і GNU Classpath та Apache Harmony , здається, є ідентичними стандартній реалізації Conditionінтерфейсу)
pthread_cond_wait()реальне питання, "чому pthread_cond_wait має помилкові пробудження?" .