如何从另一个线程唤醒一个线程?
How to wake up a thread from another thread?
为了说明我的问题,由于我们正处于彩蛋期,这里是情节提要:
第一个字符是一个时钟,它周期性地给出时间。但是这个时钟非常喜怒无常:它不回答询问时间的用户,而是定期通知他的所有观察者,并且这个时间段是随机定义的。
我的第二个角色是一只压力很大的兔子。除非他知道时间,否则这只兔子什么也做不了。当他完成他的动作时,他会再次询问时间并等待得到它再做其他事情。
我可以添加其他角色(一只猫,一个疯帽子制造者......)但对于这个例子,这是没有必要的。
因此,在 Java 中,我将拥有一个可供观察者观察的时钟,无论观察者的类型如何;和一只兔子,它是一种观察者。我想保留 «observable / observer» 模式,因为时钟不知道也不关心谁是观察者。
这是我正在使用的 class :
时钟
public class Clock implements Runnable, ClockObservable {
private Long time;
public Clock () {
}
@Override
public void run() {
while (true) {
time=System.currentTimeMillis();
update();
try {
int randomTimeUpdate=(int)( (Math.random() + 1) *500); //This clock will update randomly
Thread.sleep(randomTimeUpdate);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void update() {
for (ClockObserver observer : observers) {
observer.update(time);
}
}
}
ClockObservable
import java.util.ArrayList;
public interface ClockObservable {
public static ArrayList<ClockObserver> observers = new ArrayList<ClockObserver>();
public default void addObserver (ClockObserver observer) {
observers.add(observer);
}
public default void resetObservers () {
observers.clear();
}
public void update ();
}
ClockObserver
public interface ClockObserver {
public void update(Long time);
}
兔子
public class Rabbit implements ClockObserver {
Long time;
public Rabbit (Clock clock) {
clock.addObserver(this);
whatTimeIsIt();
}
public synchronized void whatTimeIsIt () {
while (true) {
System.out.println("What time is it ?");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("It's "+time+" -> Yepeeeee !!!! I can do something before asking the time again...");
System.out.println("-----------------------------------");
}
}
@Override
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»
}
}
主要
public class Main {
public static void main(String[] args) {
Clock clock = new Clock();
Thread thread = new Thread (clock);
thread.start();
new Rabbit(clock);
}
}
问题是 Rabbit class 中的以下指令,在覆盖的更新方法中,生成了 «java.lang.IllegalMonitorStateException»。
Rabbit.this.notifyAll();
而且,实际上,Rabbit 在主线程上,而通知在线程 0 上。
但是,我能做什么呢?如何解决我的问题?
谢谢大家的回答。
Dr_Click
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
除非通知另一个线程共享状态已更改。
您当前的代码没有任何意义,因为它没有等待 for 任何东西,也没有通知 about 任何东西。 notify
/wait
函数没有信号量的语义。他们没有自己的共享状态。你必须实现共享状态。
如果兔子处于等待状态,您需要在某处保存兔子状态的变量,并且需要将其设置为 "waiting"。然后,当你想改变兔子的状态时,你需要将该状态更改为"running"。然后兔子可以等待它的状态设置为 "running" 并且另一个线程可以通知它它的状态已经改变。但是您没有实现任何共享状态,因此没有什么可等待的,也没有什么可通知的。当然,那个状态变量需要用锁来保护。
兔子应该有 while (state == waiting) wait();
这样的代码,另一个线程可以有 state = running; notifyAll();
这样的代码。然后兔子实际上在等待 something 并且另一个线程修改了一些共享状态,它可能需要通知另一个线程 about。当然只有在持有锁的情况下才能更改或测试状态。
此外,为什么 update
不是 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("-----------------------------------");
}
}
注意线程现在如何等待 某些东西?并注意到两个线程之间是如何共享状态的?
为了说明我的问题,由于我们正处于彩蛋期,这里是情节提要: 第一个字符是一个时钟,它周期性地给出时间。但是这个时钟非常喜怒无常:它不回答询问时间的用户,而是定期通知他的所有观察者,并且这个时间段是随机定义的。 我的第二个角色是一只压力很大的兔子。除非他知道时间,否则这只兔子什么也做不了。当他完成他的动作时,他会再次询问时间并等待得到它再做其他事情。 我可以添加其他角色(一只猫,一个疯帽子制造者......)但对于这个例子,这是没有必要的。
因此,在 Java 中,我将拥有一个可供观察者观察的时钟,无论观察者的类型如何;和一只兔子,它是一种观察者。我想保留 «observable / observer» 模式,因为时钟不知道也不关心谁是观察者。
这是我正在使用的 class :
时钟
public class Clock implements Runnable, ClockObservable {
private Long time;
public Clock () {
}
@Override
public void run() {
while (true) {
time=System.currentTimeMillis();
update();
try {
int randomTimeUpdate=(int)( (Math.random() + 1) *500); //This clock will update randomly
Thread.sleep(randomTimeUpdate);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void update() {
for (ClockObserver observer : observers) {
observer.update(time);
}
}
}
ClockObservable
import java.util.ArrayList;
public interface ClockObservable {
public static ArrayList<ClockObserver> observers = new ArrayList<ClockObserver>();
public default void addObserver (ClockObserver observer) {
observers.add(observer);
}
public default void resetObservers () {
observers.clear();
}
public void update ();
}
ClockObserver
public interface ClockObserver {
public void update(Long time);
}
兔子
public class Rabbit implements ClockObserver {
Long time;
public Rabbit (Clock clock) {
clock.addObserver(this);
whatTimeIsIt();
}
public synchronized void whatTimeIsIt () {
while (true) {
System.out.println("What time is it ?");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("It's "+time+" -> Yepeeeee !!!! I can do something before asking the time again...");
System.out.println("-----------------------------------");
}
}
@Override
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»
}
}
主要
public class Main {
public static void main(String[] args) {
Clock clock = new Clock();
Thread thread = new Thread (clock);
thread.start();
new Rabbit(clock);
}
}
问题是 Rabbit class 中的以下指令,在覆盖的更新方法中,生成了 «java.lang.IllegalMonitorStateException»。
Rabbit.this.notifyAll();
而且,实际上,Rabbit 在主线程上,而通知在线程 0 上。
但是,我能做什么呢?如何解决我的问题?
谢谢大家的回答。
Dr_Click
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
除非通知另一个线程共享状态已更改。
您当前的代码没有任何意义,因为它没有等待 for 任何东西,也没有通知 about 任何东西。 notify
/wait
函数没有信号量的语义。他们没有自己的共享状态。你必须实现共享状态。
如果兔子处于等待状态,您需要在某处保存兔子状态的变量,并且需要将其设置为 "waiting"。然后,当你想改变兔子的状态时,你需要将该状态更改为"running"。然后兔子可以等待它的状态设置为 "running" 并且另一个线程可以通知它它的状态已经改变。但是您没有实现任何共享状态,因此没有什么可等待的,也没有什么可通知的。当然,那个状态变量需要用锁来保护。
兔子应该有 while (state == waiting) wait();
这样的代码,另一个线程可以有 state = running; notifyAll();
这样的代码。然后兔子实际上在等待 something 并且另一个线程修改了一些共享状态,它可能需要通知另一个线程 about。当然只有在持有锁的情况下才能更改或测试状态。
此外,为什么 update
不是 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("-----------------------------------");
}
}
注意线程现在如何等待 某些东西?并注意到两个线程之间是如何共享状态的?