Відповідаючи на питання ОП
Що я можу зробити, щоб розбудити це очікування неправдиво, не чекаючи вічно випадкової події?
, жоден хибний пробудження не міг розбудити цю очікувану нитку!
Незалежно від того , паразитні пробуджень може або не може статися на конкретній платформі, в разі ФП - х фрагмент коду це позитивно неможливо для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 має помилкові пробудження?" .