在实现一个的生产者和消费者(以下简称PC问题(producer-consumer))。遇到了一些问题;
在实现中使用ArrayBlockingQueue,这是一个有最大容量的阻塞队列,在队列中添加元素有3种方式,我想使用put方法,这样不用判断是否队列已经满了,同样取元素使用take,不用判断队列是否为空。
public class Producer implements Runnable {
Random random = new Random();
@Override
public void run() {
while(true){
try {
//模拟生产的时间
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int id = TestSolution.GoodId.incrementAndGet();
int s = random.nextInt(TestSolution.goodsName.length);
Good good = new Good(id, TestSolution.goodsName[s]);
try {
TestSolution.goods.put(good);
System.out.println(Thread.currentThread().getName() + " 生产了 " + good.toString() + "----已经有产品个数" + TestSolution.goods.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
// TestSolution.goods.notify();
//运行上面的会报错
}
}
}
public class Consumer implements Runnable {
@Override
public void run() {
try {
_run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void _run() throws InterruptedException{
while (true) {
//模拟消费的时间
Thread.sleep(1500);
{
Good good = TestSolution.goods.take();
System.out.println(Thread.currentThread().getName() +
" 消费了 " + good.toString() + "----还有剩余产品个数" + TestSolution.goods.size());
}
//TestSolution.goods.notify();
//运行上面的会报错
}
}
}
public class TestSolution {
public static final int MaxSizeOfGoods = 10;
public static final int ProducerNum =3;
public static final int ConsumerNum =3;
public static AtomicInteger GoodId = new AtomicInteger(0);
public static ArrayBlockingQueue<Good> goods= new ArrayBlockingQueue<>(10);
public static String goodsName[]= {"娃哈哈", "可口可乐","雪碧","啤酒"};
public static void main(String[] args) {
for(int i=0;i<ProducerNum;i++){
Thread thread = new Thread(new Producer(),"生产者"+(i+1));
thread.start();
}
for(int i=0;i<ConsumerNum;i++){
Thread thread = new Thread(new Consumer(),"消费者"+(i+1));
thread.start();
}
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上面的代码主要体现了一个问题,在线程处理过程中不需要显式加锁,但是注意下面的结果;
可以看到由于没有对阻塞队列对象加锁,所以 在打印队列中元素的个数时候会出现问题。但是如果我们只需要PC,不需要阻塞队列对象的信息,那么是可以接受的。
如果一定要阻塞队列的信息准确也很好办,只需要对阻塞队列(goods)进行加锁就行,不需要notify。
通过这个代码,我们可以看到put在队列满的时候,会自动释放锁,进入阻塞状态,而唤醒(notify)也不需要我们主动关心。