阻塞队列(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

使用场景

  • 生产者消费者模式
  • 线程池
  • 消息中间件
原文地址:https://www.cnblogs.com/ding-dang/p/13156232.html