<p id="main-toc"><strong>目录</strong></p>
讯享网
一、了解阻塞队列
1、什么是阻塞队列
2、应用场景
3、标准库的阻塞队列
二、模拟实现阻塞队列
1、实现普通队列
2、实现线程安全
3、实现阻塞功能
4、优化
阻塞队列也是一种先进先出的队列,但是它还具有以下特性:
(1) 是线程安全的队列;
(2) 带有阻塞功能:
(a) 如果队列满,继续入队列时,入队列操作就会阻塞,直到队列不满才能完成入队列;
(b) 如果队列空,继续出队列时,出队列操作就会阻塞,直到队列不空才能完成出队列。
阻塞队列的典型应用场景:生产者消费者模型
生产者消费者模型是一种常见的多线程协调工作的模式:生产者和消费者之间通过阻塞队列进行通讯,生产者生产出数据不用等待消费者来处理,而是会直接放入到阻塞队列中;消费者也不找生产者索要数据,而是直接从阻塞队列中取。
类似于我们去超市买东西:老板作为“生产者”,他把商品放在货物架上让我们自己拿,我们作为“消费者”,也不需要直接去找老板要商品,而是直接去相应的货物架上拿它就行,这个货物架就相当于“交易场所”。
如果每个逛超市的人都去找老板说:“老板,我要一个xxx”,那么老板就会非常忙,放在代码中,就是会产生严重的锁冲突。
生产者消费者模型的作用:
(1) 有利于代码“解耦合”
生产者不用关心消费者的存在,消费者也不需关心生产者的存在,通过阻塞队列可以降低二者的关联关系。
(2) “削峰填谷”

阻塞队列相当于一个“缓冲区”,平衡了生产者和消费者的处理能力。
标准库中的阻塞队列是一个接口:BlockingQueue
实现该接口的类:
入队列方法:put(E e)
出队列方法:take()
注意:
(1) offer(E e)方法也可以入队列,但是这个方法不具有阻塞功能。
(2) 阻塞队列无法阻塞式的查看队首元素,只能先取出队首元素,查看之后再放入队列中。
阻塞队列的简单使用:
讯享网

进程此时并没有结束,因为主线程还在阻塞等待...
首先我们使用顺序表的方式简单实现一个队列:
我们刚才实现的put和take方法的几乎每一行代码都涉及到读写操作,所以在多线程环境下,这种非原子操作一定是不安全的,我们需要对这两个方法进行加锁,并用volatile修饰相应的变量,来保证线程安全:
讯享网
注意:两个方法中加锁的对象必须是同一个对象 。
我们需要实现两个阻塞功能:
(1) 队列满,继续入队列会阻塞,直到有元素出队;
(2) 队列空,继续出队列会阻塞,直到有元素入队。
可以使用wait和notify来进行线程阻塞和唤醒线程的操作:
两个方法中的wait和notify会相互唤醒:

虽然我们刚才实现了阻塞功能,但是等待中的线程如果被唤醒后发现队列还是空或满的状态,那么继续执行代码仍然会出错,比如通过interrupt方法唤醒等待中的线程…
所以当线程被唤醒时,我们需要再次判断队列是否为空或满的状态,如果是,则继续等待,如果不是,则执行后面的逻辑:
讯享网
将if条件判断换成while循环判断即可解决上述问题
以上就是模拟实现阻塞队列的最终版本

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/186321.html