生产者消费者注意细节

今天听了马老师的生产者消费者问题,里面提到一些细节,以前写的时候没注意,特地记录一下:

class Pool<T> {

private final int MAX = 20;
private volatile int top = 0;
List<T> list = new ArrayList<>(MAX);

public synchronized void put(T e) throws InterruptedException {
//第一个要注意的问题,这里要用while进行判断。
while(top == MAX) {
wait();
}
list.add(top, e);
top++;
//第二个问题,这里要用notifyAll。
notifyAll();
}

public synchronized T get() throws InterruptedException {
while(top == 0) {
wait();
}
top--;
T t = list.get(top);//其实这里有内存泄漏,用remove(top)可能好点。
notifyAll();
return t;
}

public int getSize() {
return top;
}
}

以上代码中,要注意的地方有两点:
1.put和get时,判断栈是否为空或是否为满要用while而不能用if
举个反栗,如果使用if进行判断的话:
a:多个生产者要执行put方法,发现Pool已经满了,放不进去了,此时这些生产者均会进入wait状态;
b:此时有一个消费者消费了一个产品,并唤醒了生产者们;
c:生产者1获得锁,向Pool中放入一个产品,top变成了MAX;
d:不巧,生产者2接着获得锁,打算再放入一个产品,即执行list.add(top,e),这下完犊子了吧,放进去的东西超过MAX了。
所以要用while,当一个线程被唤醒后,不会立即对Pool执行修改,而是再次进行检测,某种程度上类似于Singleton的双重检测机制:

public class Singleton {  
 private volatile static Singleton instance = null;  
 private Singleton() {}  
 public static Singleton getInstance() {  
  if (instance == null) {  
   synchronized (Singleton.class) {
    if (instance == null) {
     instance = new Singleton();
    }  
   }  
  }  
  return instance;  
 }  
}  

2.要用notifyAll而不是notify
举个反例,用notify而没有用notifyAll
似乎反例不太好举,马老师举得例子不太实际,他说:
消费者全wait了
生产者只有一个醒着的,现在Pool里有MAX-1个产品,那么该生产者生产完放入,唤醒了另一个生产者,
接下来,这俩生产者看到Pool满了,都相继进入wait,结果就是死锁。

我想来想去都想不通他说的这种:消费者都进入wait而生产者竟然没唤醒消费者的青黄是如何发生的。

不管则么说,用notifyAll肯定是最保险的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值