• 阻塞式队列


    目录

    1.阻塞队列是什么

    2.阻塞队列中一个最重要的应用场景 :生产者消费者模型

     3.Java标准库中阻塞队列的简单使用

    4.阻塞队列的实现


    1.阻塞队列是什么

    阻塞队列是一种特殊的队列,也遵守"先进先出"的原则。这里注意不要和操作系统内核里,表示阻塞状态的 PCB 的那个链表混为一谈了!!

    阻塞队列能够保证线程安全,它有以下特性:

    🍃1.当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素。

    🍃2.当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素。


    2.阻塞队列中一个最重要的应用场景 :生产者消费者模型

    什么是生产者消费者模型呢??

    🍁 【举例】

     按照上图中的方案二包饺子,会出现两种情况:

    🍃1.生产者擀皮速度惊人,还没等消费者使用,盖帘就摆满了,所以它就停下来休息一会。

    🍃2.生产者生产的速度跟不上消费者消耗擀皮的速度,于是就出现,盖帘里没有擀皮的情况,于是消费者就等待休息一会。

    我们把这种模型就叫做生产者消费者模型!!

    生产者消费者模型的优点

    🍁优点一:可以做到更好的"解耦合"

    🍁优点二:能够做到"削峰填谷",提高整个系统的抗风险能力!!

     所以我们就需要利用生产者消费者模型来解决这种问题!!


     3.Java标准库中阻塞队列的简单使用

    1. public class TestDemo1 {
    2. public static void main(String[] args) {
    3. BlockingQueue blockingQueue = new LinkedBlockingQueue<>();
    4. Thread customer = new Thread(() -> {
    5. while(true) {
    6. try {
    7. int value = blockingQueue.take();
    8. System.out.println("消费元素: " + value);
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. }
    13. });
    14. customer.start();
    15. Thread producer = new Thread(() -> {
    16. int n = 0;
    17. while(true) {
    18. try {
    19. System.out.println("生产元素: " + n);
    20. blockingQueue.put(n);
    21. n++;
    22. Thread.sleep(500);
    23. } catch (InterruptedException e) {
    24. e.printStackTrace();
    25. }
    26. }
    27. });
    28. producer.start();
    29. }
    30. }


    4.阻塞队列的实现

    🍃基于数组的方式来实现

    🍃两个核心方法put入队列)和 take出队列

    🍁【实现代码】

    1. public class MyBlockingQueue {
    2. //假定数组最大容量为 1000
    3. private int[] elem = new int[1000];
    4. //队头
    5. private int front = 0;
    6. //队尾
    7. private int rear = 0;
    8. //阻塞队列中有效数据个数
    9. volatile private int size = 0;
    10. //入队列
    11. public void put(int value) throws InterruptedException {
    12. synchronized (this) {
    13. while(size == elem.length) {
    14. //队列满了,入队阻塞等待
    15. this.wait();
    16. }
    17. elem[rear] = value;
    18. rear++;
    19. if(rear == elem.length) {
    20. //如果 rear 到达数组末尾,就让它重新从 0 开始
    21. rear = 0;
    22. }
    23. size++;
    24. //插入元素后,就可以把 出队列 唤醒了
    25. this.notify();
    26. }
    27. }
    28. //出队列
    29. public Integer take() throws InterruptedException {
    30. int ret = 0;
    31. synchronized (this) {
    32. while(size == 0) {
    33. //队列为空,出队阻塞等待
    34. this.wait();
    35. }
    36. ret = this.elem[front];
    37. front++;
    38. if(front == elem.length) {
    39. front = 0;
    40. }
    41. size--;
    42. //取走元素后,就可以把 入队列 唤醒了
    43. this.notify();
    44. }
    45. return ret;
    46. }
    47. }

    🍁【基本步骤】

    🍃1.通过 "循环队列" 的方式来实现;

    🍃2.使用 synchronized 进行加锁控制; 

    🍃3.put 插入元素的时候, 判定如果队列满了, 就进行 wait

    🍃4.take 取出元素的时候, 判定如果队列为空, 就进行 wait

    🍁【重点分析】

    🍃1.出队,入队,以及元素个数 ++,-- 等等都涉及到线程安全问题,判空、判满,里面又用到了 wait(),而 wait() 方法的第一步就是释放锁,所以 synchronized 要将它们全部包裹住。

    🍃2.理解队列为空时,出队需等待,插入元素后,即可唤醒出队;队列为满时,插入队列需等待,取出元素后,即可唤醒入队

    🍃3.入队和出队操作涉及到了读和写,给 size 变量加上 volatile 防止编译器优化,指令重排序影响 size 的值。

    🍃4.为什么判空判满时需要加上循环,结合下图理解:

    🍁【测试代码】

    1. public class Test {
    2. public static void main(String[] args) {
    3. MyBlockingQueue queue = new MyBlockingQueue();
    4. Thread customer = new Thread(() -> {
    5. while(true) {
    6. try {
    7. //消费元素
    8. int value = queue.take();
    9. System.out.println("消费: " + value);
    10. } catch (InterruptedException e) {
    11. e.printStackTrace();
    12. }
    13. }
    14. });
    15. customer.start();
    16. Thread producer = new Thread(() -> {
    17. int value = 0;
    18. while(true) {
    19. try {
    20. //生产元素
    21. queue.put(value);
    22. System.out.println("生产: " + value);
    23. value++;
    24. Thread.sleep(500);
    25. } catch (InterruptedException e) {
    26. e.printStackTrace();
    27. }
    28. }
    29. });
    30. producer.start();
    31. }
    32. }

    🍁【分享掌握技巧】

    1.理解如何使用;

    2.理解内部的实现原理;

    3.能够模拟实现;

    4.能给别人清楚的讲出来。(写博客就是在给别人讲)!!


    本篇博客就到这里了,谢谢观看!!

  • 相关阅读:
    2023年中职“网络安全“—Web 渗透测试②
    js中给数组添加元素的方法有哪些
    Python爬虫——BautifulSoup 节点信息
    AIGC专栏7——EasyPhoto 人像训练与生成原理详解
    游戏心理学Day28
    【PHPWord】如何解决PHPWord的输出checkbox复选框并设置checked已勾选
    微擎手机端传图总是提示4M限制修改
    【国科方案】设置引脚复用、方向和输入输出
    视频处理工具安利,要制作视频的快来
    混沌学院-亚朵酒店案例-观后随心谈
  • 原文地址:https://blog.csdn.net/xaiobit_hl/article/details/126035318