⭐ 作者:小胡_不糊涂
🌱 作者主页:小胡_不糊涂的个人主页
📀 收录专栏:JavaEE
💖 持续更文,关注博主少走弯路,谢谢大家支持 💖
阻塞队列
- 1. 什么是阻塞队列
- 2. 标准库中的阻塞队列
- 3. 模拟实现
1. 什么是阻塞队列
阻塞队列是⼀种特殊的队列,遵守 “先进先出” 的原则。
阻塞队列能是⼀种线程安全的数据结构,并且具有以下特性:
- 当队列满的时候,继续⼊队列就会阻塞,直到有其他线程从队列中取⾛元素。
- 当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插⼊元素。
阻塞队列的⼀个典型应⽤场景就是 “⽣产者消费者模型”。这是⼀种⾮常典型的开发模型。
生产者消费模型:
⽣产者消费者模式就是通过⼀个容器来解决⽣产者和消费者的强耦合问题。
⽣产者和消费者彼此之间不直接通讯,⽽通过阻塞队列来进⾏通讯,所以⽣产者⽣产完数据之后不⽤等待消费者处理,直接扔给阻塞队列,消费者不找⽣产者要数据,⽽是直接从阻塞队列⾥取
- 阻塞队列就相当于⼀个缓冲区,平衡了⽣产者和消费者的处理能力
- 阻塞队列也能使⽣产者和消费者之间解耦
2. 标准库中的阻塞队列
在 Java 标准库中内置了阻塞队列。如果我们需要在⼀些程序中使⽤阻塞队列,直接使⽤标准库中的即可。
- BlockingQueue 是⼀个接⼝,真正实现的类是 LinkedBlockingQueue
- put ⽅法⽤于阻塞式的⼊队列,take ⽤于阻塞式的出队列
- BlockingQueue 也有 offer, poll, peek 等⽅法,但是这些⽅法不带有阻塞特性
示例:
public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue=new ArrayBlockingQueue<>(100);queue.put("aaa");//入队列--有阻塞功能的String elem=queue.take();//出队System.out.println(elem);//aaa
}
3. 模拟实现
方法:
- 先实现普通队列–使用数组实现循环队列,保证实现出入队列的操作
- 加上线程安全–synchronized
- 加上阻塞队列
//模拟实现
class MyBlockingQueue{private String[] elems=null;//数组实现队列private int head=0;//队首private int tail=0;//队尾private int size=0;//元素个数private Object loker=new Object();//锁对象public MyBlockingQueue(int capacity){elems=new String[capacity];}//入队列public void put(String elem) throws InterruptedException {//有读写操作的synchronized (loker) {//队列满了,进入阻塞while(size >= elem.length()) {loker.wait();}elems[tail] = elem;//新元素放入tail位置上tail++;//tail=tail%elems.length;if (tail >= elems.length) {tail = 0;//循环对列}size++;//当队列为空,只要有元素入队列就唤醒下面的waitloker.notify();}}//出队列public String take() throws InterruptedException {String tmp =null;synchronized (loker) {//队列为空while(size == 0) {loker.wait();}tmp = elems[head];head++;if (head >= elems.length) {head = 0;}size--;//当队列满了,只要有元素出队列就唤醒前面的入队列loker.notify();}return tmp;}
}