我所见过的代码并没有像我预期的那样有效。
static Integer sync = 1;
static void m() throws Exception {
synchronized (sync) {
System.err.println("First");
sync.notify();
sync.wait(1000L);
System.err.println("Second");
System.err.println("Third");
}
}
public static void main(String[] args) throws Exception {
Runnable r = new Runnable() {
@Override
public void run() {
try {
m();
} catch (Exception ex) {
Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Runnable t = new Runnable() {
@Override
public void run() {
try {
m();
} catch (Exception ex) {
Logger.getLogger(IO.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread th1 = new Thread(r);
Thread th2 = new Thread(t);
th1.run();
th2.run();
}
我们有两个线程执行m()
的syncjronized语句。当第一个线程执行一个并遇到wait()
时,它将被添加到等待集中。在此之后,第二个线程开始执行synchronized语句,并执行notify()。由于输出必须
First
First
....
但实际上它是
First
Second
Third
First
Second
Third
为什么?
答案 0 :(得分:4)
首先,您的程序没有创建任何线程。您必须调用th1.start()和th2.start()来创建线程。
t.start()是库为您启动线程时要调用的代码提供的方法。 run()是你为库提供在新线程中调用的方法。您的run()方法定义了线程将执行的操作。 IMO,run()是一个非常误导的名字。
其次,通知()和等待()不要做你认为他们会做的事情。特别是,如果当前没有其他线程在sync.wait()中,sync.notify()根本不会做任何事情。
使用notify()和wait()的正确方法是,一个线程执行此操作:
synchronized(lock) {
while (! someCondition()) {
lock.wait()
}
doSomethingThatRequiresSomeConditionToBeTrue();
}
另一个线程执行此操作
synchronized(lock) {
doSomethingThatMakesSomeConditionTrue();
lock.notify();
}
使用此模式时,除了在同步(锁定)块内部之外,任何线程都不应更改someCondition()的结果。
答案 1 :(得分:1)
首先,要实际创建新线程,请使用
th1.start() th2.start()
inplace of run(),它只是对线程对象的常规方法调用。
其次,第二个帖子可能是第二个' th'在1000毫秒被填充时没有开始运行,所以第一个线程完成了等待(1000)并执行了剩余的代码行。
如果您想要输出如下:
first
first
second
third
second
third
然后删除wait()的时间间隔,这将使线程等到通知为止。 如:
static void m() throws Exception {
synchronized (sync) {
System.err.println("First");
sync.notify();
sync.wait();
System.err.println("Second");
System.err.println("Third");
}
}
答案 2 :(得分:1)
使用.start()
代替run()
将可运行的内容添加到队列中而不是立即运行它们
Documentation表示wait
超时等待此对象上的任何notify
或超时。在你的情况下,一个接一个地执行runnables它会:
PS。调用run()
而没有设置超时会导致t等待死锁,因为它已经有了对象,但是等待永远不会被通知。
希望这有帮助。