今天用wait()和notify()进行线程通信实现输出12A34B56C.....格式的长字符,写了一段看起来很不成熟的代码,然后还把自己绕晕了= =、原来是因为在for循环里使用if-elseif结构调用wait方法导致出错,找了好久的bug终于反应过来了,为了下次不再犯类似的错误,在这里进行一下总结。
下面就是我那不太成熟的代码:
//打印字母的线程类
public class PrintAlphabet implements Runnable {
private MyPrint myprint;
@Override
public void run() {
myprint.printAlphabet();
}
public PrintAlphabet(MyPrint myprint) {
super();
this.myprint = myprint;
}
}
//打印数字的线程类
public class PrintCount implements Runnable{
private MyPrint myprint;
@Override
public void run() {
myprint.printCount();
}
public PrintCount(MyPrint myprint) {
super();
this.myprint = myprint;
}
}
//打印字母的方法
public synchronized void printAlphabet(){
for(;number<78;number++){
if(number%3==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else if(number%3==1){
System.out.println("老大number:"+number+"----->"+countnumber+++" ");
}
else if(number%3==2) {
System.out.println("老二number:"+number+"----->"+countnumber+++" ");
notifyAll();
}
}
}
//打印数字的方法
public synchronized void printCount(){
for(;number<78;number++){
if(number%3==1||number%3==2){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else if(number%3==0){
System.out.println("老三number:"+number+"----->"+(char) alphabetnumber+++" ");
notifyAll();
}
}
}
运行结果如下:
后面仔细检查发现自己蠢哭了,原来每次回到wait()的地方都没有进行重新判断number的值,而是直接结束了本次循环。所以具体过程应该是这样的:
首先number等于1打印出老大,然后继续循环打印出老二,当运行到number等于3之后甲线程wait,在乙线程输出来老三,然后调用nitifyAll()唤醒线程甲,但是要先number加一等于4之后线程甲才回到之前wait的地方,但是因为我没有用while重新进行判断,所以执行完wait就直接结束本次循环number又加一等于5,直接跟着打印出了老二,这就解释了上面运行结果为什么缺了老大,继续number加一等于6,此时线程1就wait了。然后又回到第二个线程wait的地方开始运行,还是因为没有重新判断,所以这个时候又直接加一为7,所以线程2也wait了。
解决办法:1.把for循环改成while循环
2.把if-elseif-结构改成if-if-if结构
总结: 其实看代码发现,其实我的wait()方法也是放在循环中的,只是因为我用的是for循环,又使用if-elseif结构进行判断,这就导致了每次重新回到了wait的地方都不能继续往下执行,而如果我用while循环就不会出现这种情况了。