#java #multithreading #concurrency
#java #многопоточность #параллелизм
Вопрос:
В настоящее время я читаю эффективную Java, и я нахожусь в главе о параллелизме. При объяснении причин, по которым поток может проснуться, когда условие не выполняется (условие цикла while, в котором выполняется вызов wait()), есть одна причина, которая меня довольно смущает, и я, похоже, не могу ее понять.
Другой поток мог получить блокировку и изменить защищенное состояние между моментом, когда поток вызвал уведомление, и ожидающий поток проснулся.
Может кто-нибудь попытаться объяснить это предложение?
Ответ №1:
Это проще всего объяснить на примере:
public class ConditionTest implements Runnable {
private boolean flag;
public void run() {
try {
synchronized (this) {
while (true) {
this.wait();
if (flag) {
System.out.printf("%s: my condition is truen",
Thread.currentThread().getName());
flag = false;
} else {
System.out.printf("%s: my condition is false!!n",
Thread.currentThread().getName());
}
}
}
} catch (InterruptedException ex) {
// bail out
}
}
public static void main(String[] args) throws InterruptedException {
ConditionTest ct = new ConditionTest();
new Thread(ct).start();
new Thread(ct).start();
new Thread(ct).start();
Thread.sleep(1000);
while (true) {
synchronized(ct) {
ct.flag = true;
ct.notifyAll();
}
Thread.sleep(1000);
}
}
}
Условием в этом примере является то, что runnable flag
должно быть true
. Рабочие потоки сообщают о состоянии условия, а затем сбрасывают флаг.
Как вы можете видеть, метод main создал и запустил три потока, совместно использующих runnable. Затем он повторно устанавливает флаг в true и уведомляет рабочих.
Когда рабочий разбужен, он может обнаружить, что флаг является false
; т. Е. Его условие не выполняется. На самом деле, если вы запустите приведенный выше код, вы увидите, что это происходит два раза из трех.
Почему?
Потому что, если рабочий видит это flag == true
, он снимает флаг! Поэтому, когда другие рабочие просыпаются, они видят очищенный флаг.
Это то, о чем говорится в тексте в кавычках.
По общему признанию, в данном случае это вызвано нашим сомнительным notifyAll
вызовом, но применяется общий принцип. Вы должны проверить условие.
На некоторых платформах также возможно (или было) возникновение ложных уведомлений; т. Е. Уведомлений, Которые не являются результатом какого-либо notify
или notifyAll
вызова из кода приложения.