我见过wait
和notify
的很多例子,但我仍有问题。
public class Main(){
public static void main(String args[]) throws Exception {
MyThread s = new MyThread();
s.start();
}
}
class MyThread extends Thread {
public void run() {
k();
}
public synchronized void k() {
System.out.println("before wait");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("do something after wait");
}
public synchronized void m() {
for (int i=0;i<6;i++)
System.out.println(i);
notify();
}
}
运行程序时我得到的唯一输出是:"before wait"
。
答案 0 :(得分:0)
问题是,您没有调用m
方法,因此永远不会调用notify
,因此您的线程会永远休眠。您可以在开始之后使用main
:
s.m()
中调用它
MyThread s = new MyThread();
s.start();
s.m();
也许你应该sleep
在调用m
方法之前花一点时间,因为它可能比线程中的k
更快地运行:
s.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// nothing to do
}
s.m();
与问题没有密切关系,但throws
中的main
声明不太明确,即使生成的printStackTrace
比抛出异常更好。
答案 1 :(得分:0)
您在main
中创建的主题调用MyThread#k()
进入等待状态。此时,该线程在被唤醒或中断之前不会执行任何其他操作。但是代码中可能被唤醒的唯一位置是notify
中的MyThread#m()
。由于程序中没有任何内容调用该方法,因此线程永远不会被唤醒。
您可能希望在主程序中s.m()
之后立即添加对s.start()
的调用。这样你的主线程就会执行唤醒你的线程所需的notify
。
不幸的是,这不太可行。问题是s.start()
导致您创建的线程准备好运行,但它不一定立即运行。您可能会在创建的线程执行任何操作之前完成对s.m()
的调用。然后你仍然会得到与之前完全相同的结果,除了你会在before wait
之前看到打印出的整数0..6。 notify
将不执行任何操作,因为子线程尚未执行其wait
。 (顺便说一句,由于MyThread#k()
和MyThread#m()
都是同步的,因此增加MyThread#m()
中的循环限制不会改变事物......子线程将无法实现在MyThread#k()
正在运行时输入MyThread#m()
。您可以通过将notify
置于同步块中而不是使所有MyThread#m()
同步来改善这一点。)
您可以尝试在主程序中Thread.sleep(1000)
之前添加s.m()
来解决此问题。这几乎肯定会起作用,因为你的主线程将产生执行,让你的JVM有机会安排子线程进行一些有用的工作。当主线程退出睡眠并执行s.m()
调用时,孩子可能已经执行了wait
,然后您将看到do something after wait
消息。
但这仍然非常糟糕,因为它仍然取决于您实际上无法控制的日程安排事件。仍然没有保证 wait
将在notify
之前发生。
这就是为什么在使用wait / notify时你应该安排一些可靠的测试,以确定你是否还在等待完成。这应该是一个条件,一旦它变为真,将至少在随后进行测试之前保持为真。然后你的典型等待循环看起来像这样:
while (!isDone()) {
synchronized(monitorObject) {
try {
monitorObject.wait();
} catch (InterruptedException e) {
}
}
}
把整个东西放在一个循环中会照顾过早的醒来,例如由于InterruptedException。
如果在执行此代码时已经发生了所需的工作,则不会发生wait
,并且执行该工作的代码执行的notify
是无操作的。否则,此代码会等待,完成工作的代码最终将执行notify
,这将根据需要唤醒此代码。当然,至关重要的是,在notify
执行时,等待条件(上面isDone()
)为真,并且至少在测试之前保持为真。
以下是包含正确等待循环的代码的更正版本。如果您注释掉Thread.sleep()
来电,则可能看不到waiting
消息,因为工作将在等待循环开始之前完成。包含睡眠后,您可能会看到waiting
消息。但不管怎样,程序都能正常运行。
public static void main(String[] argv) throws Exception {
MyThread s = new MyThread();
s.start();
Thread.sleep(1000);
s.m();
}
class MyThread extends Thread {
@Override
public void run() {
k();
}
private boolean done = false;
public void k() {
System.out.println("before wait");
while (!done) {
System.out.println("waiting");
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
System.out.println("do something after wait");
}
public void m() {
for (int i = 0; i < 6; i++) {
System.out.println(i);
}
synchronized (this) {
done = true;
notify();
}
}
}