设为首页 加入收藏

TOP

Java 生产者消费者模式详细分析(二)
2018-01-17 13:05:40 】 浏览:594
Tags:Java 生产者 消费者 模式 详细 分析
句处继续向下消费刚生产完的面包,假设正好再次唤醒了消费线程2,当消费线程2被CPU选中后,消费线程2也将从wait语句处向下消费,消费的也是刚才生产的面包,问题再此出现了,连续唤醒的消费线程1和2消费的是同???个面包,也就是说面包被重复消费了。这又是多线程不同步问题。


说了一大段,其实将视线放大后分析就很简单了,只要某一方的2个或多个线程都因为判断b.flag而wait,那么这两个或多个线程有可能会被连续唤醒而继续向下生产或消费。这造成了多线程不同步问题。


不安全的问题就出在同一方的多个线程在连续唤醒后继续向下生产或消费。这是if语句引起的,如果能够让wait的线程在唤醒后还回头判断b.flag是否为true,就能让其决定是否继续wait还是向下生产或消费。


可以将if语句替换为while语句来满足要求。这样一来,无论某一方的多个线程是否被连续唤醒,它们都将回头判断b.flag。


解决了第一个多线程安全的问题,但会出现死锁问题。这很容易分析,将生产方看作一个整体,将消费方也看作一个整体,当生产方线程都wait了(生产方的线程被连续唤醒时会出现该方线程全部wait),消费方也都wait了,死锁就出现了。其实放大了看,将生产方、消费方分别看作一个线程,这两个线程组成多线程,当某一方wait后无法唤醒另一方,另一方也一定会wait,于是就死锁了。


对于双方死锁的问题,只要保证能唤醒对方,而非本方连续唤醒就能解决。使用notifyAll()或signalAll()即可,也可以通过signal()唤醒对方线程解决,见下面的第二段代码。


根据上面的分析,将单生产、单消费模式的代码改进一下,就可以变为多生产多消费单面包模式。、


以下是采用Lock和Conditon重构后的代码,使用的是signal()唤醒对方线程的方法。


关于多生产、多消费问题做个总结:


 


有多个生产者线程,多个消费者线程,生产者将生产的面包放进篮子(集合或数组)里,消费者从篮子里取出面包。生产者判断继续生产的依据是篮子已经满了,消费者判断继续消费的依据是篮子是否空了。此外,当消费者取出面包后,对应的位置又空了,生产者可以回头从篮子的起始位置继续生产,这可以通过重置篮子的指针来实现。


在这个模式里,除了描述生产者、消费者、面包,还需要描述篮子这个容器。假设使用数组作为容器,生产者每生产一个,生产指针向后移位,消费者每消费一个,消费指针向后移位。


代码如下:可参考API-->Condition类中给出的示例代码


这里涉及了消费者、生产者、面包和篮子,其中面包和篮子是多线程共同操作的资源,生产者线程生产面包放进篮子,消费者线程从篮子中取出面包。理想的代码是将生产任务和消费任务都封装在资源类中,因为面包是篮子容器的元素,所以不适合封装到面包类中,而且封装到篮子中,能更方便地操作容器。


注意,一定要将所有涉及资源操作的代码都放进锁的内部,否则会产生多线程不同步问题。例如,在Producer类中定义了生产面包的方法produce(),然后将其作为放进篮子的方法basket.in()的参数,即basket.in(producer()),这是错误的行为,因为produce()是在锁的外部执行后才传递给in()方法的。


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇RabbitMQ消息分发轮询和Message A.. 下一篇Python字符编码详细分析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目