• 基础 | 并发编程 - [阻塞队列]


    §1 什么是阻塞队列

    阻塞队列的存取性质与普通队列一致,即先进先出
    同时,阻塞队列提供具有下面特性的存取方法

    • 若队列是的,获取操作阻塞,直到其他线程向其中存入元素
    • 若队列是的,存入操作阻塞,直到其他线程向其中获取元素或清空队列

    §2 阻塞队列有什么好处

    阻塞队列可以在上述条件下自动阻塞(挂起)线程,
    随后,在满足条件时自动唤醒线程
    编写逻辑时,不用考虑线程相关的问题,而只需要专注于容器
    原始多线程实现方式见 基础 | 并发编程 - [Lock 使用 & 对比 synchronized] 中示例

    §3 阻塞队列总览

    类型一览

    类型是否有界数据结构特性备注
    ArrayBlockingQueue数组
    LinkedBlockingQueue链表虽然有界,但默认情况下大小为 Integer.MAX_VALUE,约等于无界
    PriorityBlockingQueue×支持优先级取操作或获取优先级最高或最低的元素,而不完全按顺序
    DelayBlockingQueue×支持优先级,延迟
    SynchronousQueue不存储元素,一个存或取操作到达此队列就被阻塞,直到另一个与之配对的取或存操作到来,一起放行
    LinkedTransferQueue×链表约等于 SynchronousQueue + LinkedBlockingQueue,无界,所以 put() 并不阻塞,但可以通过 transfer() 阻塞的使消费者消费
    LinkedBlockingDeque链表双向

    特性说明

    • 有界
      队列的长度是由限制的
    • 无界
      队列的长度没有限制,可以扩充至资源耗尽
    • 支持优先级
      队列中的元素具有优先级,从队列中获取元素时会得到优先级最高或最低的元素
    • 双向
      队列不再是只能从一端存入从另一端获取
      而是两端都可以存取
      可以作为栈或队列使用

    常用 api 一览
    作为容器,阻塞队列的核心功能也是
    但阻塞队列为存取提供了多个接口,并配合多种反馈效果

    • 阻塞
      能存取时存取,不能存取时等待
      直到 有空位可以存有元素可以取
      §1 什么是阻塞队列
    • 超时
      能存取时存取,不能存取时先阻塞
      直到 有空位可以存有元素可以取,或超时
      超时时返回标记值
    • 标记值
      能存取时存取,不能存取时返回标记值(false / null)
    • 抛异常
      能存取时存取,不能存取时抛异常

    element() 和 peek() 会返回队列的第一个元素
    但队列为空(empty)时,前者抛异常,后者返回 null

    阻塞put(e)take()
    超时offer(e,time,unit)poll(e,time,unit)
    标记值offer(e)poll()peek()
    异常add(e)remove()element()

    通用 api 示例
    仅以 ArrayBlockingQueue 为例

        public static void main(String[] args) {
            BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
            try {
                // 阻塞卡死 ============================================
                queue.put("a");
                System.out.println("put 1 over"); // put 1 over
                queue.put("b"); // block here
                System.out.println("put 2 over"); //not output
                queue.take();
                System.out.println("take 1 over"); // take 1 over
                queue.take(); // block here
                System.out.println("take 2 over"); //not output
    
                // 阻塞后恢复 ============================================
                queue.put("c");
                System.out.println("put 3 over"); // put 3 over
                new Thread(()->{
                    // block here, until thread named "BBB" is over
                    try { queue.put("C"); } catch (InterruptedException e) { e.printStackTrace(); }
                },"AAA").start();
                new Thread(()->{
                    // take the "c" out
                    try { TimeUnit.SECONDS.sleep(1); queue.take(); } catch (InterruptedException e) { e.printStackTrace(); }
                },"BBB").start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 先阻塞,超时后返回标记值 ============================================
            try {
                queue.offer("a",1L,TimeUnit.SECONDS); // true
                queue.offer("b",1L,TimeUnit.SECONDS); // 1 second later, false
                queue.poll(1L,TimeUnit.SECONDS); // a
                queue.poll(1L,TimeUnit.SECONDS); // 1 second later, null
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 标记值 ============================================
            queue.offer("a"); // true
            queue.offer("b"); // false
            queue.peek(); // first element
            queue.poll(); // a
            queue.poll(); // null
            queue.peek(); // null
    
            // 一言不合抛异常  ============================================
            queue.add("a"); // true
            queue.add("b"); // java.lang.IllegalStateException: Queue full
            queue.element(); // first element
    
            queue.remove(); // element
            queue.remove(); // java.util.NoSuchElementException
            queue.element(); // java.util.NoSuchElementException
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    §4 SynchronousQueue

    SynchronousQueue 不存储元素,存入一个元素后,此元素不取出,不能存入另一个元素
    Synchronous 的意思是指此队列会使一对存取操作同步,如果不能达成同步则会阻塞,直到等到另一个匹配的操作

    public static void main(String[] args) {
        SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>();
    
        new Thread(()->{
            System.out.println("1 <--");
            try { queue.put(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("2 <--");
            try { queue.put(2); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("3 <--");
            try { queue.put(3); } catch (InterruptedException e) { e.printStackTrace(); }
        }).start();
    
        new Thread(()->{
            try { TimeUnit.SECONDS.sleep(2);queue.take(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("1 ---->");
            try { TimeUnit.SECONDS.sleep(2);queue.take(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("2 ---->");
            try { TimeUnit.SECONDS.sleep(2);queue.take(); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("3 ---->");
        }).start();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

  • 相关阅读:
    vue2计算属性
    java计算机毕业设计学生选课系统源码+系统+mysql数据库+lw文档+部署
    JavaScript数据结构【准备】
    【Flink实战】新老用户方案优化使用状态与布隆过滤器的方式
    OpenStack学习笔记-Glance组件深入了解
    线下Meetup:在数智化转型背景下,火山引擎VeDI的大数据技术揭秘
    SpringMVC_day01
    2153. The Number of Passengers in Each Bus II(当时不会)(NO)
    【【萌新的FPGA学习之实战流水灯】】
    JAVA互联网一线大厂面试真题自测,顺便看看大牛的通行证
  • 原文地址:https://blog.csdn.net/ZEUS00456/article/details/126534049