public void update(Long time) {
this.time=time;
System.out.println("Time = "+time);
//How can I notify the rabbit ?
Rabbit.this.notifyAll(); //This cause a «java.lang.IllegalMonitorStateException»
}
Функция notifyAll
используется для уведомления других потоков об изменении какого-либо общего состояния. Общее состояние здесь не изменилось, поэтому нет ничего, о чем можно было бы уведомить другие темы. Если вы думаете, this.time
является общим состоянием, то объясните, почему несинхронизированный метод изменяет его без удержания какой-либо блокировки. Вы не можете сделать это с общим состоянием.
public synchronized void whatTimeIsIt () {
while (true) {
System.out.println("What time is it ?");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
Та же проблема здесь. Вы звоните wait
, не проверяя, что то, чего вы ждете, еще не произошло. Чего ты ждешь? Каково общее состояние, которое находится не в том состоянии, в котором оно должно быть?
Представьте себе, если один поток собирается вызвать wait
, но планировщик задерживает его. Затем другой поток вызывает notifyAll
. Ваш поток все равно будет вызывать wait
, потому что он не проверяет общее состояние, чтобы увидеть, должно ли оно ждать.
Вы не можете использовать wait
, кроме как ждать, пока какой-то фрагмент общего состояния будет иметь некоторое ценность. Вы не можете использовать notify
, кроме как для уведомления другого потока об изменении общего состояния.
Ваш текущий код просто не имеет никакого смысла, потому что он не ждет для ничего и не является он уведомляет о о чем угодно. Функции notify
/ wait
не имеют семантики семпахоров. У них нет своего общего государства. Вы должны реализовать общее состояние.
Если кролик находится в состоянии ожидания, где-то вам нужна переменная, которая хранит состояние кролика, и его нужно установить в «ожидание». Затем, когда вы хотите изменить состояние кролика, вам нужно изменить это состояние на «бегущий». Затем кролик может подождать, пока его состояние станет «запущенным», а другой поток может уведомить его об изменении его состояния. Но вы не реализовали ни одного общего состояния, поэтому ждать нечего и не о чем уведомлять. И, конечно, эта переменная состояния должна быть защищена блокировкой.
Кролик должен иметь код, подобный while (state == waiting) wait();
, а другой поток может иметь код, подобный state = running; notifyAll();
. Затем кролик ожидает что-то , а другой поток изменил некое общее состояние, которое может потребоваться уведомить другой поток о . Конечно, состояние следует изменять или проверять только удерживая блокировку.
Кроме того, почему не метод update
a synchronized
? Он меняет time
, который является общим.
Вот еще один вариант:
public synchronized void whatTimeIsIt () {
Long last_time = time; // make local copy
while (true) {
System.out.println("What time is it ?");
try {
while (time == last_time)
wait();
last_time = time;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("It's "+time+" -> Yepeeeee !!!! I can do something before asking the time again...");
System.out.println("-----------------------------------");
}
}
Обратите внимание, как поток теперь ждет для чего-то? И обратите внимание, как это нечто разделяет состояние между двумя потоками?