JUC之阻塞队列

什么是阻塞队列

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是: 在队列为空时, 获取元素的线程会等待队列变为非空。当队列满时, 存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景, 生产者是往队列里添加元素的线程, 消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器, 而消费者也只从容器里拿元素。

  • 当队列是空的, 从队列中获取元素的操作将会被阻塞
  • 当队列是满的, 从队列中添加元素的操作将会被阻塞
  • 试图从空的队列中获取元素的线程将会被阻塞, 直到其他线程往空的队列插入新的元素
  • 试图向已满的队列中添加新元素的线程将会被阻塞, 直到其他线程从队列中移除一个或多个元素或者完全清空, 使队列变得空闲起来并后续新增

阻塞队列种类

  1. ArrayBlockingQueue

    • 基于数组构成的有界阻塞队列
    • 在生产者插入数据和消费者获取数据时用的是同一把锁, 无法并行
  2. LinkedBlockingQueue

    • 基于链表构成的有界(默认值为Integer.MAX_VALUE)阻塞队列
    • 插入数据和获取数据分别采用了独立的锁, 有较好的并发性能
  3. DelayQueue

    • 基于优先级队列实现的延迟无界阻塞队列
    • DelayQueue 中的元素只有当其指定的延迟时间到了, 才能够从队列中获取到该元素。
    • DelayQueue 是一个没有大小限制的队列, 因此往队列中插入数据的操作永远不会被阻塞, 只有获取数据的操作才会被阻塞
  4. PriorityBlockingQueue

    • 基于优先级队列实现的无界阻塞队列
    • 支持优先级排序
    • 不会阻塞生产者, 当队列中没有数据时, 会阻塞消费者
  5. SynchronousQueue

    • 一种无缓冲的等待队列
    • 相对于有缓冲的BlockingQueue来说, 少了一个中间环节(缓冲区)
    • 不存储元素, 是一个单个元素的队列

    SynchronousQueue公平模式与非公平模式的区别

    • 公平模式: SynchronousQueue 会采用公平锁, 并配合一个 FIFO 队列来阻塞多余的生产者和消费者, 从而体系整体的公平策略
    • 非公平模式(默认):SynchronousQueue 采用非公平锁, 同时配合一个 LIFO 队列来管理多余的生产者和消费者, 再高并发的情况下容易出现线程饥饿
  6. LinkedTransferQueue

    • 基于链表结构实现的无界TransferQueue队列
    • 预占模式: 意思就是消费者线程取元素时, 如果队列不为空, 则直接取走数据, 若队列为空, 生成一个节点(元素为 null)入队, 消费者线程被等待在这个节点上, 生产者线程入队时发现有一个元素为 null 的节点, 生产者线程就不入队了, 直接就将元素填充到该节点, 并唤醒该节点等待的线程, 被唤醒的消费者线程取走元素, 从调用的方法返回
  7. LinkedBlockingDeque

    • 基于链表实现的双向有界阻塞队列
    • 可以从队列的两端插入和移除元素, 双向队列因为多了一个操作队列的入口, 在多线程同时入队时, 也就减少了一半的竞争
    • 插入元素时: 如果当前队列已满将会进入阻塞状态, 一直等到队列有空的位置时再该元素插入, 该操作可以通过设置超时参数, 超时后返回 false 表示操作失败, 也可以不设置超时参数一直阻塞, 中断后抛出 InterruptedException异常
    • 读取元素时: 如果当前队列为空会阻塞住直到队列不为空然后返回元素, 同样可以通过设置超时参数

核心方法

方法类型抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e, time, unit)
移除remove()poll()take()poll(time, unit)
检查element()peek()NANA

各种方法类型的具体效果

方法类型效果
抛出异常当阻塞队列满时, 再往队列里add插入元素会抛出IllegalStateException:Queue full
当阻塞队列空时, 再对队列remove移除元素会抛出NoSuchElementException
特殊值插入方法, 成功返回true, 失败返回false
移出方法, 成功返回取出的元素, 失败返回null
阻塞当阻塞队列满时, 生产者线程继续往队列里put元素, 队列就会一直阻塞生产者知道put数据成功或中断退出
当阻塞队列空时, 消费者线程试图从队列里take元素, 队列就会一直阻塞消费者线程知道队列里有数据
超时当阻塞队列满时, 队列会阻塞生产者线程, 超过等待时限后生产者线程会退出
当阻塞队列空时, 队列会阻塞消费者线程, 超过等待时限后消费者线程会退出

我的个人主页: www.ayu.link
本文连接: ┏ (゜ω゜)=☞

Java中的阻塞队列(Blocking Queue)是一个多线程并发编程中常用的数据结构,它可以在某些条件下挂起线程,并在条件满足时自动唤醒。阻塞队列提供了一种线程安全的方式来实现生产者-消费者模型。 阻塞队列位于java.util.concurrent包中,简称JUC。它提供了许多与多线程并发相关的组件操作。阻塞队列可以通过以下方式进行初始化: ``` BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>(); //基于链表来实现,可以指定阻塞队列的大小 ``` 阻塞队列的核心方法有以下几种类型: 1. 插入方法:add(e)、offer(e)、put(e)、offer(e,time,unit) - 如果队列已满,再往队列中插入元素会抛出异常或返回特殊值。 2. 移除方法:remove()、poll()、take()、poll(time,unit) - 如果队列为空,从队列中移除元素会抛出异常或返回特殊值。 3. 检查方法:element()、peek() - 检查队列的头部元素,如果队列为空,element()方法会抛出异常,peek()方法会返回null。 阻塞队列的特性包括: - 抛出异常:当阻塞队列满时,再往队列中添加元素会抛出异常IllegalStateException,当阻塞队列空时,移除队列中的元素会抛出异常NoSuchElementException。 - 特殊值:插入方法成功时返回true,失败时返回false;移除方法成功时返回队列的元素,队列为空时返回null。 - 一直阻塞:当阻塞队列满时,生产者线程继续往队列中放入元素,队列会一直阻塞生产者线程,直到生产者线程put数据或响应中断退出;当阻塞队列空时,消费者线程试图从队列中取出元素,队列会一直阻塞消费者线程,直到队列可用。 - 超时退出:当阻塞队列满时,队列会阻塞线程一定时间,超过时间后生产者线程会退出。 可以通过创建多个线程作为生产者或消费者来使用阻塞队列。以下是一个示例: ```java public static void main(String[] args) { BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(); //作为交易场所 Thread t1 = new Thread() { //作为生产者 public void run() { for (int i = 0; i < 1000; i++) { try { queue.put(i); System.out.println("生产元素生产了" + i + "个"); sleep(1000); //每秒钟生产一个元素 } catch (InterruptedException e) { e.printStackTrace(); } } } }; t1.start(); Thread t2 = new Thread() { //作为消费者 public void run() { while (true) { //频繁取队首元素 int num = queue.take(); System.out.println("消费元素为" + num); } } }; t2.start(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值