java.lang.Object.wait()的不同行为
我试图使用java.lang.Object.wait()的不同行为,java,wait,notify,Java,Wait,Notify,我试图使用java.lang.Object.wait()方法,并编写了3个不同的示例代码,其中我得到了wait()方法的不同行为 样本1) 样本3) 在样本1中) main线程将永远处于等待状态正如它调用的b.wait()方法一样,并且在对象b上没有线程提供notify()或notifyAll()。在调用b.wait()方法的main线程之前,已经终止了子线程。 这个输出是我所期望的 在样本2中) main线程在打印后处于等待状态10秒(t.wait(10000);) X 开始等待 10秒后,m
java.lang.Object.wait()
方法,并编写了3个不同的示例代码,其中我得到了wait()
方法的不同行为
样本1)
样本3)
在样本1中)
main线程将永远处于等待状态正如它调用的b.wait()
方法一样,并且在对象b
上没有线程提供notify()
或notifyAll()
。在调用b.wait()
方法的main线程之前,已经终止了子线程。
这个输出是我所期望的
在样本2中)
main线程在打印后处于等待状态10秒(t.wait(10000);
)
X开始等待
10秒后,main线程执行
等待t
Y
这也是我的预期输出 在样本3中) main线程未处于等待状态(
t.wait(10000);
),即使在调用t.wait(10000)的main线程时子线程肯定已被终止代码>
那么它为什么不等待呢?并立即执行
开始等待
等待t
Y
这不是我的预期输出。对于前两个例子,您的预期似乎是正确的。在第三个示例中,可以合理地预期t将在主线程开始等待之前完成,然后主线程将挂起直到超时
但正如你所观察到的,事情并非如此
等待线程不会停止等待,除非被中断或通知(虚假唤醒除外,但这些都是不可预测的竞争条件的结果;发布的代码中的行为发生可靠,因此我认为这里可以排除虚假唤醒)
由于没有任何东西会中断主线程,并且它的等待被缩短,并且我们已经排除了虚假的唤醒,因此它必须接收到通知。只有一种东西可以提供通知,那就是t线程
要让t通知主线程,它必须在t开始等待时处于活动状态。那么,是什么让它继续存在
当线程终止时,会发生一些不为人所知的行为。报告说:
此实现使用This.wait调用的循环,该循环以This.isAlive为条件。当线程终止时,调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll
发生的情况是:
1) t打印其输出,并且正在退出其run方法
2) 在t和主线程之间有一个座圈以获得t上的锁。t需要它调用notifyAll,main需要它进入synchronized块。主线程碰巧先抓住锁
3) 它会一直呆在那里直到它能拿到锁
4) 主线程进入等待方法(释放锁)
5) t获取锁并调用t.notifyAll
5) 主线程收到通知并离开等待方法(重新获取锁)
一些教训:
- 不要在线程上进行同步(这是一个很好的例子,说明了为什么API文档说不要这样做,在这里,您无意中延迟了一个线程,使其不能及时死亡)
- 如果线程没有等待,则不会得到通知。如果线程在通知发生后开始等待,则该通知将丢失
- 不要仅仅依赖于通知(这会使您的代码容易受到竞争条件的影响),而是将通知与其他线程可以设置的条件一起使用。使用测试条件在循环中调用wait。如果您看到Thread.join源代码,这是一个很好的示例,它看起来像:
while (isAlive()) {
wait(0);
}
- 不要拿着锁睡觉。它使系统响应速度降低,但没有任何好处
- 对事情发生的顺序进行假设时要非常小心
您不应该在线程实例上同步,也不应该将其用作监视器。它让人困惑,而且它不做你认为它做的事情,而且它可能与线程的内部结构冲突。@AdriaanKoster-我知道synchronized关键字的作用。这是学习wait()方法工作的示例代码。正如Mark所说,不要在线程对象上同步。在任何其他对象上同步(我建议new object()
)并在该对象上调用wait()
,将使您的wait
调用按预期进行。@Nathanhues请在您的答案部分查看我的评论。Thanks@Nathan-你说的是矛盾的话。。。“发生的事情是t打印其输出,然后主线程抓住锁,直到主线程等待(释放锁),t才有机会拿回它。对于t,它需要调用notifyAll,如果不获取自己的锁,它就不能这样做。它会阻塞,直到能够获取锁。”正如上面的行所示。。线程t获取其锁并调用notifyAll(),然后在main方法释放锁后终止。但实际上这就是问题所在,主线程甚至没有等待(t.wait(10000);@raven03:main线程调用wait。notifyAll生效时,等待被缩短,这导致线程从等待中返回。当然,它需要重新获取锁才能做到这一点,但是在调用notifyAll之后,它不会释放锁,所以锁是可用的。不清楚什么是矛盾的。@NathanHughes您如何解释下面程序的输出--public class Main{public static void Main(String[]args)抛出InterruptedException{Thread t=new Thread(){public void run(){System.out.println(“我是第二个线程”);};t.start();System.out.println
public class Main{
public static void main (String[] args) throws InterruptedException {
Thread t = new Thread();
t.start();
System.out.println("X"); //--> 1
synchronized(t) {
System.out.println("starting to wait"); //--> 2
t.wait(10000);
System.out.println("waiting on t"); //--> 3
}
System.out.println("Y"); //--> 4
}
}
public class Main{
public static void main (String[] args) throws InterruptedException {
Thread t = new Thread() {public void run()
{System.out.println("I am the second thread.");}};
t.start();
System.out.println("X"); //--> 1
synchronized(t) {
Thread.sleep(4000);
System.out.println("starting to wait"); //--> 2
t.wait(10000);
System.out.println("waiting on t"); //--> 3
}
System.out.println("Y"); //--> 4
}
}
while (isAlive()) {
wait(0);
}