当前位置: 首页 > Thinking in Java > 正文

第21章 – 并发 – 单一 生产者与消费者,多个生产者与多个消费者(P709)

第21章 – 并发 – 单一 生产者与消费者,多个生产者与多个消费者(P709)

 

1. 单一 生产者与消费者:一个餐馆只有一个厨师(生产者)和一个服务员(消费者)

 

   代码如下,使用单一的锁restaurant.lockObj来协调厨师和服务员.

   当meal为null时,服务员等待,厨师开始工作,反之服务员工作,厨师等待.

 

   一个餐馆和一个厨师时,这种代码运行正常.

 

2. 当有多个厨师(生产者)和多个服务员(消费者)时,如果在单一锁上同步,则有产生死锁的风险.

 

   将上面例子中 myRestaurant.run(); 

   改成myRestaurant.run(10,10);即可启动10个厨师和10个服务员

   但是 因为在单一锁上同步,则有产生死锁的风险,

   而且,这种在同一个锁上同步的,将所有步骤的代码都放到synchronized中,

   采用多个生产者消费者也没有意义(性能提升意义不大).

   同一时刻,只能有一个生产者(或消费者)在运行.

 

3. 考虑一种场景: 即 餐馆中有若干个厨师和若干个服务员,厨师生产的meal放到mealList中,

   当mealList.size() < maxMealCount时,厨师开始生产meal,否则等待

   当mealList.size() > minMealCount 时,服务员开始消费meal,否则等待

   多个厨师和服务员可以同时工作,以便提升服务速度.

 

   问题分析:

   现实生活中之所以需要多个厨师是因为,厨师生产meal是耗时的,即 new Meal()这个操作是耗时的,

   另外,每个厨师制作meal是独立的,也就是说,使用多个生产者在new Meal()时可以独立运行,不用同步,所以

   多个厨师可以同时并行生产meal,这样可以加快制作meal的速度,就相当于提升了性能.

 

   对于每个服务员来说,拿到meal后,将meal送达制定餐桌是耗时的操作,同时也是独立的.

 

   这里需要注意的是,厨师做好的meal放入mealList时需要同步处理,因为可能有多个厨师同时想要

   将meal放入mealList,并且也可能有多个服务员打算从mealList中获取一个meal.

 

   同步处理时,判断

   当mealList.size() < maxMealCount时,厨师开始生产meal,否则等待

   当mealList.size() > minMealCount 时,服务员开始消费meal,否则等待

 

   另外,在多个厨师和多个服务员时,厨师调用锁的notifyAll()时,可能会唤醒其他厨师的线程,导致

   这个唯一唤醒的线程又进入wait()了.所以使用synchronized(锁对象)的方式不适用于这里的多生产

   者和多消费者的条件.

 

   这里使用Lock和Condition. 一个Lock 的两个condition(cChefs和cWaitPerson)

   在cChef await()的时候,调用cWaitPerson的signalAll(),只通知WaitPerson

   在cWaitPerson await()时,调用cChef的signalAll(),只通知Chef

   避免死锁.

   代码如下:

 

 

打个赏呗

   微信打赏  支付宝打赏


本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2140.html | 边城网事

该日志由 边城网事 于2015年03月18日发表在 Thinking in Java 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 第21章 – 并发 – 单一 生产者与消费者,多个生产者与多个消费者(P709) | 边城网事
关键字: ,

第21章 – 并发 – 单一 生产者与消费者,多个生产者与多个消费者(P709) 暂无评论

发表评论

快捷键:Ctrl+Enter