在下面的代码中,我使用wait() - notify()实现了线程间通信,它给了我预期的输出。 预期产出:123456789实际产量:123456789
我的问题是,是否有任何保证始终'主线程'将获得第一次执行的机会,因为线程调度依赖于jvm。如果'子线程'获得第一次机会,notify()信号将错过,主线程'将永远等待。我怎样才能确认主线程'将永远执行。另外请确认以下代码是否可以改进。
package com.test.Thread;
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException{
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj .start();
synchronized(lockingObj ){
for(int i=1;i<10;i++){
System.out.println("Main "+i);
}
lockingObj.wait();
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println("Child "+i);
}
this.notify();
}
}
}
答案 0 :(得分:3)
您的代码错误是因为您提到了自己:您无法确定哪个线程首先出现。
还有其他可能出错的问题 - wait
可以在没有notify
的情况下醒来。
您可以在Javadoc for the wait
method中阅读相关内容,这也解释了您应该做的事情:
在一个参数版本中,中断和虚假唤醒是 可能,这个方法应该总是在循环中使用:
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
在你的代码中,你可以用一个表达条件的布尔变量来解决它&#34;我收到了通知&#34;:
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException {
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj.start();
synchronized (lockingObj) {
for(int i = 1; i < 10; i++) {
System.out.println("Main " + i);
}
while (!lockingObj.haveNotified) {
lockingObj.wait();
}
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
private boolean haveNotified;
public void run(){
synchronized (this) {
for (int i = 1; i < 10; i++) {
System.out.println("Child " + i);
}
haveNotified = true;
this.notify();
}
}
}
答案 1 :(得分:1)
虽然这在您的系统上正常工作,但它并不是一种保证,因为您的怀疑可能会在另一个系统上变为现实。线程行为很难/无法预测。因此,我喜欢在最坏的情况下思考,如果我能想出一个可能的突破情况(正如你刚才描述的那样),我只需重新设计以确保它能够正常工作。
测试代码的一个好方法是在关键时刻暂停/暂停线程,方法是在IDE中添加断点,在可能的情况下添加一个非常耗时的任务/调用(不是故障保护),或者通过虚拟暂停线程(并不总是理想的)。此外,我确信有一些库可以扩展这种类型的测试。
我希望这能帮助你朝着正确的方向前进。