生产者消费者多线程一个例子中while和notifyall的作用

代码如下

public synchronized void put(Object o) {  
          while (buf.size()==MAX_SIZE) {  
              wait(); // 如果buffer为full,就会执行wait方法等待(为了简单,我们省略try/catch语句块)  
          }  
          buf.add(o);  
          notify(); // 通知所有正在等待对象锁的Producer和Consumer(译者注:包括被阻挡在方法外的Producer和Consumer)  
     }  
        
     // Y: 这里是C2试图获取锁的地方(原作者将这个方法放到了get方法里面,此处,我把它放在了方法的外面)  
     public synchronized Object get() {  
          while (buf.size()==0) {  
              wait(); // 如果buffer为Null,就会执行wait方法(为了简单,同样省略try/catch语句块)  
              // X: 这里是C1试图重新获得锁的地方(看下面代码)  
          }  
          Object o = buf.remove(0);  
          notify(); // 通知所有正在等待对象锁的Producer和Consumer(译者注:包括被阻挡在方法外的Producer和Consumer)  
          return o;  
     }

 这里如果不用while用if会出现什么情况呢:(生产者P,消费者C)

1.buf.size() == 0时,C1进入,if判断为真,wait(抛出锁);C2在外等待

2.P1获得锁,add后buf == 1,唤醒C1

3.被唤醒的C1和C2抢锁,C2获得锁执行remove,此时buf.size()==0

4.C1此时获得锁,继续往下执行buf.remove但是此时buf.size()==0,抛出IndexArrayOutOfBoundsException

这里使用while判断就能避免此问题

这里使用notify会有什么问题呢,情景如下:(max_size == 1)

1.P1执行

2.P2,P3想put但是buf.size()==1 两个都wait

3.C1,C2同时想get,C1获得锁,get完buf.size()==0 并唤醒P2

4.C2,P2抢锁C2抢得,wait

5.P2获得锁Put后,buf.size()==1 唤醒P3

6.P3获得锁 wait 此时C2和P3同时wait,没有线程能notify了

如果使用notifyall可避免这种情况

猜你喜欢

转载自xiaoxiaoher.iteye.com/blog/2356152
今日推荐