代码如下
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可避免这种情况