wordpress搭建下载站点,微信小游戏开发工具,wordpress弹窗提示,代发货网站建设目录
一、阻塞队列
1. 生产者消费者模型
#xff08;1#xff09;解耦合
#xff08;2#xff09;“削峰填谷”
2. 标准库中的阻塞队列
3. 自己实现一个阻塞队列#xff08;代码#xff09;
4. 自己实现生产者消费者模型#xff08;代码#xff09; 一、阻塞队列…目录
一、阻塞队列
1. 生产者消费者模型
1解耦合
2“削峰填谷”
2. 标准库中的阻塞队列
3. 自己实现一个阻塞队列代码
4. 自己实现生产者消费者模型代码 一、阻塞队列 阻塞队列同样是一个符合先进先出的队列相比于普通队列阻塞队列还有其他的功能
1. 线程安全2. 产生阻塞效果1如果队列为空尝试出队列就会出现阻塞阻塞到队列不为空为止2如果队列满了尝试入队列就会出现阻塞阻塞到队列不为满为止。基于上述特点的阻塞队列我们就可以实现“生产者消费者模型”。处理多线程问题的一个典型方式。
1. 生产者消费者模型 生产者消费者模型通过一个容器阻塞队列来解决生产者消费者之间的强耦合问题。生产者生产商品消费者购买商品 开发实际生活中使用的 阻塞队列 并不是一个简单的数据结构而是一组专门的服务器程序。里面也不仅仅包含了阻塞队列的功能还有其他的功能。这样的队列叫做 “消息队列” 。
1解耦合 假设现在有两个服务器 A 和 B A 作为入口服务器直接接收用户的网络请求B 作为应用服务器给 A 提供服务。
假设不使用 生产者消费者模型 即生产者和消费者之间直接进行沟通则具有 强耦合性 。 强耦合性 体现在 当开发 A 代码的时候就得充分了解 B 提供的一些接口开发 B 代码的时候也得充分了解到 A 是怎么调用的。当我们想把 B 换成 C 时A 的代码就得发生较大的改动并且如果 B 崩溃了也可能导致 A 也崩溃。 因此强耦合性是一种不好的现象。 而生产者消费者模型刚好可以降低这里的耦合即模块和模块之间的联系尽可能的少。 当 A 给 B 发送请求时A 先将请求写到阻塞队列中然后 B 再从阻塞队列中取出请求。当 B 返回结果时先把结果放到阻塞队列中然后 A 再从阻塞队列中取出结果。
请求A 是生产者B 是消费者响应A 是消费者B 是生产者阻塞队列作为交易场所使用了生产者消费者模型后A 只需要关注如何和队列进行交互不需要认识 B B 也是如此。当 B 崩溃时对 A 没有影响。A 崩溃时 B 也没有影响。相应的如果将 B 换做 C A 也完全感知不到。 就达到了解耦合的目的。
2“削峰填谷” 使用生产者消费者模型能够对于请求进行“削峰填谷”。类似水库 - 当雨季时可以利用水库正常为稻田送水当旱季时打开水库同样可以保证为稻田正常送水 还是使用上述 A 和 B 服务器的例子。假设我们没有使用生产者消费者模型 削峰 当有大量请求时A 服务器作为入口服务器计算量轻不会造成太大影响。而因为强耦合性B 也会突然暴涨B 作为应用服务器计算量比 A 大得多可能就直接造成崩溃了。 如果使用了生产者消费者模型遇到请求暴涨的情况 A 的请求暴涨导致了阻塞队列的暴涨因为阻塞队列只是存储数据因此没有太大影响。B 这边依然按照原来的速度消费数据不会因为 A 的暴涨而引起暴涨。因此 B 就被保护起来了不会因为这种请求暴涨而崩溃即 削峰 。让 B 感受不到
填谷 当 A 的请求很少而 B 依然会按照原来的速度消费数据。虽然 A 的请求少但是阻塞队列中还有挤压的数据就能够让 B 正常运行。
2. 标准库中的阻塞队列 Java标准库中自带了阻塞队列当我们编写代码时需要使用阻塞队列时直接使用即可。
BlockingQueue 是一个接口真正实现的类时 LinkedBlockingQueue。类似ListLinkedList和ArrayListput阻塞式出队列take阻塞式出队列也有 offer、poll、peek等普通队列有的方法但是这些方法不带有阻塞特性
public class Demo1 {public static void main(String[] args) throws InterruptedException {BlockingQueueString queue new LinkedBlockingDeque();//阻塞式入队列如果队列满就会阻塞queue.put(jiu);//阻塞式出队列如果队列空就会阻塞System.out.println(queue.take()); //结果为 jiu}
}
3. 自己实现一个阻塞队列代码 要实现一个阻塞队列一个普通队列 线程安全 阻塞功能 。
① 实现队列先进先出可以通过链表或者数组这里使用数组。—— 循环队列队首head 和 队尾 tail
入队列把新元素放到 tail 的位置tail出队列取出 head 位置的元素head循环队列当 head 或者 tail 到达数组末尾时就需要从头开始 0重新循环。判空 / 满要实现循环队列这是一个重要问题。我们用 变量 size 记录元素的个数进行判断。
② 实现线程安全。因为在方法中全是共享变量所以可以直接对整个方法进行加锁也可以对整个代码块进行加锁同时专门设置一个锁对象locker。
③ 实现阻塞效果。利用 wait 和 notify 来实现。使用哪个对象加锁就要用哪个对象 wait
对于 put 来说阻塞条件队列为满。而 put 中的 wait 要由 take 来唤醒。take 成功了队列就不满了对于 take 来说阻塞条件队列为空。而 take 中的 wait 要由 put 来唤醒。put 成功了队列就不为空了如果有人等待notify 可以唤醒如果没人等待notify 也没有任何影响。
//假设队列中存放的是整型元素
class MyBlockingQueue {private int[] array new int[1000];private int size 0;private int head 0;private int tail 0;private Object locker new Object();//阻塞式入队列public void put(int value) throws InterruptedException {synchronized(locker) {if (size array.length) {//说明队列满了无法再入队列了//所以进入阻塞状态locker.wait();}//队列没有满可以入队列//1.把值放到 tail 的位置array[tail] value;tail;//2.判断是否到队尾的情况等价于 tail tail % array.lengthif (tail array.length) {tail 0;}//3.sizesize;//入队列成功队列非空从阻塞队列中唤醒 takelocker.notify();}}//阻塞式出队列public int take() throws InterruptedException {synchronized(locker) {if (size 0) {//队列为空没有元素可以出//进入阻塞状态locker.wait();}//队列中有元素可以出队列//1.取出 head 位置的值int ans array[head];head;//2. 判断是否到队尾if (head array.length) {head 0;}//3. size--size--;//出队列成功队列不为满从阻塞队列中唤醒 putlocker.notify();return ans;}}
}
4. 自己实现生产者消费者模型代码
public class Demo2 {//自己实现生产者消费者模型public static MyBlockingQueue queue new MyBlockingQueue();public static void main(String[] args) {Thread producer new Thread(() - {int num 0;while(true) {try {queue.put(num);System.out.println(生产了 num);num;//让生产者生产慢一点消费者就得跟着生产者的步伐Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();Thread customer new Thread(() - {while(true) {try {int num queue.take();System.out.println(消费了 num);} catch (InterruptedException e) {e.printStackTrace();}}});customer.start();}
}