Проблема с автобоксом. Когда вы изменяете flag
с истинного на ложное или наоборот, вы фактически получаете совершенно новый Boolean
объект. То есть эта строка:
flag = false;
Эквивалентно:
flag = new Boolean(false);
Как только это происходит, ваши два потока ссылаются на два разных объекта Boolean
, поэтому их флаги оказываются несинхронизированными, и ни один из потоков не может дать сигнал другому проснуться. Когда OddThread
изменяет флаг, EvenThread
все еще имеет старый объект флага, поэтому он не видит новое значение.
Поскольку объект Boolean
является неизменным, вам необходимо изменить свой флаг, чтобы использовать какой-либо другой изменяемый объект, который может изменять значения на месте, не создавая новые объекты. То есть, или оба класса ссылаются на общую (возможно, глобальную) переменную.
Как @erickson предлагает вам использовать AtomicBoolean
, который является изменяемым. Еще один хитрый способ сделать это - изменить flag
на:
boolean[] flag = new boolean[1];
А затем используйте flag[0]
везде. Тогда оба потока смогут изменять flag[0]
, всегда ссылаясь на один и тот же boolean[]
объект массива. У вас не будет проблемы с автобоксом.
...
Кроме того, неплохо бы обернуть любой вызов wait()
в цикл. wait()
может подвергаться ложным пробуждениям, когда вызов возвращается, хотя на самом деле никто не звонил notify()
. Чтобы обойти это, вы всегда должны проверять состояние охраны после пробуждения, чтобы убедиться, что пробуждение не является ложным.
while (flag == true) {
lock.wait();
}
Обновление
Я внес изменения на основе ваших предложений выше; но я не получаю ожидаемый результат. Я вставлю модифицированный код выше. Вот результат, который я получаю 1 2 4 3 5 6 8 7 9 10 11 13 12 15 17 14 ....
Когда вы в конечном итоге ждете, когда вы проснулись, вы не переключаете flag
и не уведомляете другой поток. Я советую немного реорганизовать ваш код, чтобы он выглядел как «подожди; напечатай; уведомь». Что-то вроде:
synchronized (lock) {
while (flagObj.flag == false) {
lock.wait();
}
System.out.println(i);
flagObj.flag = false;
lock.notify();
}