zoukankan      html  css  js  c++  java
  • 阻塞队列(BlockingQueue)

    概念

    • 首先它是一个队列,而一个阻塞队列在数据结构中所起的作用大致如图所示:

    • 当阻塞队列是空时,从队列中获取元素的操作将会被阻塞

    • 当阻塞队列是满时,往队列里添加元素的操作将会被阻塞

    核心方法

    • 抛异常:如果操作不能马上进行,则抛出异常

    • 特定的值:如果操作不能马上进行,将会返回一个特殊的值,一般是 true 或者 false

    • 阻塞:如果操作不能马上进行,操作会被阻塞

    • 超时:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是 true 或者 false

    实现类

     官方的7种实现:

    • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列,此队列按 FIFO(先进先出)对元素进行排序
    • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列,此队列按 FIFO(先进先出)对元素进行排序,吞吐量通常要高于ArrayBlockingQueue。此队列的默认和最大长度为 Integer.MAX_VALUE,可以认为是无界
    • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列
    • DelayQueue:一个使用优先级队列实现的无界阻塞队列
    • SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlokcingQueue
    • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列
    • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列

     ArrayBlockingQueue 和LinkedBlockingQueue区别

    • 底层实现不同
      • ArrayBlockingQueue 底层使用数组来维护队列
      • LinkedBlockingQueue 底层使用链表来维护队列,在添加和删除队列中的元素的时候,会创建和销毁节点对象,在高并发和大量数据的时候,GC压力很大
    • 锁的方式不同
      • ArrayBlockingQueue 获取数据和添加数据都是使用同一个锁对象,不过,在ArrayBlockingQueue 中使用Condition的等待/通知机制,这样使得ArrayBlockingQueue的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜
      • LinkedBlockingQueue  获取数据和添加数据使用不同的锁对象

     SynchronousQueue

    实际上它不是一个真正的队列,因为它不会为队列中元素维护存储空间。与其他队列不同的是,它维护一组线程,这些线程在等待着把元素加入或移出队列

    public class SynchronousQueueDemo {
    
        public static void main(String[] args) {
            SynchronousQueue<Integer> synchronousQueue = new SynchronousQueue<>();
            new Thread(() -> {
                try {
                    synchronousQueue.put(1);
                    TimeUnit.SECONDS.sleep(3);
                    synchronousQueue.put(2);
                    TimeUnit.SECONDS.sleep(3);
                    synchronousQueue.put(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            new Thread(() -> {
                try {
                    Integer val = synchronousQueue.take();
                    System.out.println(LocalDateTime.now().toString() + "---------" + val);
                    Integer val2 = synchronousQueue.take();
                    System.out.println(LocalDateTime.now().toString() + "---------" + val2);
                    Integer val3 = synchronousQueue.take();
                    System.out.println(LocalDateTime.now().toString() + "---------" + val3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
    
    // 输出:
    // 2020-06-18T10:21:07.615---------1
    // 2020-06-18T10:21:10.496---------2
    // 2020-06-18T10:21:13.497---------3

    使用场景

    • 生产者消费者模式
    • 线程池
    • 消息中间件
  • 相关阅读:
    VC++学习(1):Windows程序内部运行原理
    VC++学习(9):定制应用程序外观
    VC++学习(7):对话框编程
    VC++学习(3):MFC框架程序剖析
    VC++学习(5):文本编程
    VC++学习(4):简单绘图
    DbgPrint/KdPrint输出格式控制
    常用的正则表达式
    使用geoserver+openLayers加载google地图
    retunValue与opener的用法
  • 原文地址:https://www.cnblogs.com/ding-dang/p/13156232.html
Copyright © 2011-2022 走看看