到底什么是阻塞队列?有啥用?

沙海 2021年3月11日12:20:06杂谈 Java评论28字数 3114阅读10分22秒阅读模式
摘要

速读摘要

速读摘要文章源自JAVA秀-https://www.javaxiu.com/3411.html

阻塞队列是一个支持阻塞的插入和移除的队列。阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里获取元素的线程。如果是移除方法,则是从队列中取出一个元素,没有则返回null。当阻塞队列满时,如果生产者线程往队列里面put元素,则生产者线程会被阻塞,知道队列不满或者响应中断退出。当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定时间,生产者线程就会退出。文章源自JAVA秀-https://www.javaxiu.com/3411.html

原文约 1207 | 图片 0 | 建议阅读 3 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/3411.html

到底什么是阻塞队列?有啥用?

GitHub笔记 文章源自JAVA秀-https://www.javaxiu.com/3411.html

作者:海向文章源自JAVA秀-https://www.javaxiu.com/3411.html

地址:www.cnblogs.com/haixiang/p/12354520.html文章源自JAVA秀-https://www.javaxiu.com/3411.html

什么是阻塞队列

阻塞队列是一个支持阻塞的插入和移除的队列。文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • 支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • 支持阻塞的移除方法:意思是队列为空时,获取元素(同时移除元素)的线程会被阻塞,等到队列变为非空。文章源自JAVA秀-https://www.javaxiu.com/3411.html

阻塞队列用法

阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里获取元素的线程。文章源自JAVA秀-https://www.javaxiu.com/3411.html

当阻塞队列不可用时,会有四种相应的处理方式:文章源自JAVA秀-https://www.javaxiu.com/3411.html

处理方式抛出异常返回特殊值一直阻塞超时退出
插入操作add(e)offer(e)put(e)offer(e, time, unit)
移除操作remove()poll()take()poll(time, unit)
获取操作element()peek()不可用不可用
  • 返回特殊值:插入元素时,会返回是否插入成功,成功返回true。如果是移除方法,则是从队列中取出一个元素,没有则返回null。文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • 一直阻塞:当阻塞队列满时,如果生产者线程往队列里面put元素,则生产者线程会被阻塞,知道队列不满或者响应中断退出。当队列为空时,如果消费者线程从队列里take元素。文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • 超时退出:当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定时间,生产者线程就会退出。文章源自JAVA秀-https://www.javaxiu.com/3411.html

如果是无界阻塞队列,队列则不会出现满的情况。文章源自JAVA秀-https://www.javaxiu.com/3411.html

阻塞队列

  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • PriorityBlockingQueue:一个支持优先级排序无界阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • DelayQueue:一个使用优先级队列实现的无界阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • SynchronousQueue:一个不存储元素的阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

    • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列文章源自JAVA秀-https://www.javaxiu.com/3411.html

1.ArrayBlockingQueue

此队列按照先进先出(FIFO)的原则对元素进行排序文章源自JAVA秀-https://www.javaxiu.com/3411.html

默认情况下不保证线程公平地访问队列(所谓公平是指当队列可用时,先被阻塞的线程先访问队列)文章源自JAVA秀-https://www.javaxiu.com/3411.html

为了保证公平性通常会降低吞吐量。文章源自JAVA秀-https://www.javaxiu.com/3411.html

公平锁是利用了可重入锁的公平锁来实现。文章源自JAVA秀-https://www.javaxiu.com/3411.html

public ArrayBlockingQueue(int capacity, boolean fair) {    if (capacity <= 0)        throw new IllegalArgumentException();    this.items = new Object[capacity];    lock = new ReentrantLock(fair);    notEmpty = lock.newCondition();    notFull =  lock.newCondition();}文章源自JAVA秀-https://www.javaxiu.com/3411.html

2.ArrayBlockingQueue

此队列按照先进先出(FIFO)的原则对元素进行排序文章源自JAVA秀-https://www.javaxiu.com/3411.html

默认长度为Integer.MAX_VALUE文章源自JAVA秀-https://www.javaxiu.com/3411.html

3.PriorityBlockingQueue

默认情况下元素采取自然顺序升序排列文章源自JAVA秀-https://www.javaxiu.com/3411.html

可以自定义Comparator或者自定义类实现compareTo()方法来指定排序规则文章源自JAVA秀-https://www.javaxiu.com/3411.html

不支持同优先级元素排序文章源自JAVA秀-https://www.javaxiu.com/3411.html

4.DelayQueue

队列使用PriorityQueue来实现,队列中的元素必须实现Delayed接口文章源自JAVA秀-https://www.javaxiu.com/3411.html

只有在延时期满才能从队列中提取元素。Java 核心技术知识点我都整理成面试题和答案了,关注公众号Java技术栈,回复:面试,可以免费获取。文章源自JAVA秀-https://www.javaxiu.com/3411.html

阻塞队列原理

如果队列是空的,消费者会一直等待,当生产者添加元素时,消费者是如何知道当前队列有元素的呢?文章源自JAVA秀-https://www.javaxiu.com/3411.html

使用通知模式实现。所谓通知模式,就是当生产者往满的队列添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。文章源自JAVA秀-https://www.javaxiu.com/3411.html

ArrayBlockingQueue为例子文章源自JAVA秀-https://www.javaxiu.com/3411.html

/** items 存放队列中的元素*/final Object[] items;/** take 操作的索引 */int takeIndex;/** put 操作的索引 */int putIndex;/** 队列中元素个数 */int count;/** Main lock guarding all access */final ReentrantLock lock;/** 控制生产者 takes 操作的 Condition */private final Condition notEmpty;/** 控制消费者 put 操作的 Condition */private final Condition notFull;文章源自JAVA秀-https://www.javaxiu.com/3411.html

put操作文章源自JAVA秀-https://www.javaxiu.com/3411.html

public void put(E e) throws InterruptedException {    checkNotNull(e); //判断 e == null    final ReentrantLock lock = this.lock;    lock.lockInterruptibly(); //获取锁,与lock不同,可以尝试中断阻塞    try {        while (count == items.length)            notFull.await();        enqueue(e);    } finally {        lock.unlock();    }}文章源自JAVA秀-https://www.javaxiu.com/3411.html

入队操作,入队之后唤醒消费者线程。文章源自JAVA秀-https://www.javaxiu.com/3411.html

private void enqueue(E x) {    // assert lock.getHoldCount() == 1;    // assert items[putIndex] == null;    final Object[] items = this.items;    items[putIndex] = x;    if (++putIndex == items.length)        putIndex = 0;    count++;    notEmpty.signal();}文章源自JAVA秀-https://www.javaxiu.com/3411.html

notFull.await();中其实调用了park方法,先使用setBlocker保存一下将要阻塞的线程,然后调用本地方法UNSAFE.park(boolean isAbsolute, long time)进行阻塞。文章源自JAVA秀-https://www.javaxiu.com/3411.html

    public static void park(Object blocker) {        Thread t = Thread.currentThread();        setBlocker(t, blocker);        UNSAFE.park(false, 0L);        setBlocker(t, null);    }文章源自JAVA秀-https://www.javaxiu.com/3411.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定