学习Java阻塞队列必看类:BlockingQueue 了解大体框架和实现思路

前言

本文主要说明BlockingQueue类、阻塞队列使用的共同父类AbstractQueue的基础知识。后续将会逐渐探索BlockingQueue的所有实现类。


 相关性文章:

LinkedBlockingQueue 链式阻塞队列的使用方法和原理

并发相关文章:

ReentrantLock源码 解析AQS锁加锁释放锁的实现机制

CAS算法详解 ABA问题以及解决办法


目录

前言

BlockingQueue

概览

主要实现类

BlockingQueue方法的四类形式

AbstractQueue

概览

源码解析

总结


BlockingQueue

概览

1. 不接受null元素。

通过新增方法添加null元素时,会抛出空指针异常。因为null值将用作标记​​值,来指明poll操作失败。同时null值作为阻塞队列的元素也是无任何意义的。

2. 可以有容量限制,也可以没有。

当作为有界队列时,如果当队列空间不足时,add操作将会抛出IllegalStateException异常,offer将会返回false,put操作将会阻塞直到队列空间可用。

如果不设置容量大小,那么默认值是Integer.MAX_VALUE。此时可以看作无界队列;

虽然队列在逻辑上可以是无界的,但由于资源耗尽(导致OutOfMemoryError ),添加操作可能会失败。 

3. 用于生产者-消费者队列,但是同时也支持Collection的操作。

例如删除队列元素操作remove(e),但是这些操作的效率很低,一般仅用于删除某个临时取消的任务。

4. 所有实现都是线程安全的。

但是对于集合中的批量操作方法,如果其实现类没有特殊处理的话,那么addAll、containsAll、retainAll、removeAll等可能不会原子地执行。

5. 队列,整体上都基本准寻先进先出的访问顺序。

在整体上看,各个实现类是符合FIFO的顺序的。

主要实现类

LinkedBlockingQueue:链表式阻塞队列

ArrayBlockingQueue:数组式阻塞队列

PriorityBlockingQueue:优先级阻塞队列

LinkedBlockingDeque:阻塞型双端队列

DelayQueue:延时阻塞队列

SynchronousQueue:实时同步队列(没有任何存储元素的空间)

…………

BlockingQueue方法的四类形式

BlockingQueue的所有实现类的方法都分为如下四类。相对于其他的集合操作方法,put和take是实现阻塞操作的核心方法,需要重点关注。

  • Throws exception:操作未实现时(正常流程下的执行)抛出异常
  • Special value:根据操作的实际情况,返回特定值,例如null、false
  • Blocks:阻塞当前线程,直到当前线程可以成功执行
  • Times out:尝试指定时间后,放弃执行

Throws exception

Special value

Blocks

Times out

新增

add(E e)

offer(E e)

put(E e)

offer(E e, long timeout, TimeUnit unit)

删除

remove()

poll()

take()

poll(long timeout, TimeUnit unit)

查询

element()

peek()

BlockingQueue类确定了阻塞队列的整体框架,确定了各个方法的定义,因此也是了解阻塞队列一定要学习的类。

本文中大部分都是从源码注释中解读而来,同时也包含了一些自己的理解,如果表述有误,还望指出。


AbstractQueue

概览

AbstractQueue类,提供了一些Queue操作的骨架实现。

这里提及AbstractQueue的原因是,阻塞队列的大多实现类都继承该类,可以说,这个抽象类,实现了BlockingQueue的大部分通用功能。比如add、remove失败时抛出异常等等,下面会一一提及。

源码解析

这个类基本上搭建起了一个阻塞队列Throws exception形式的框架,它实现了各个抛出异常的方法。

各个方法都比较简单,关键在于了解其具体的实现思路。这对了解各个阻塞队列的实现类很有帮助。

  • add
    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

当队列空间足够时,将直接插入成功。offer方法由具体的子类实现。

如果offer插入元素成功,则add返回true ,否则将抛出IllegalStateException异常。

  • remove
    public E remove() {
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

检索并删除队列的队首元素。

它与poll不同之处仅在于,如果此队列为空,它会抛出NoSuchElementException异常。

删除成功后,返回删除的元素。

  • element
    public E element() {
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

仅获取队列的队首元素并返回结果,并不进行操作。

与peek不同之处在于,如果此队列为空,它会引发NoSuchElementException异常。

  • clear与addAll
    public void clear() {
        while (poll() != null)
            ;
    }


    public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

遍历添加或删除所有元素,实现挺简单的,不过这里并没有进行单个操作出现异常时的处理。

总结

阻塞队列了解得也差不多了,之前只是简单的学习了如何使用阻塞队列的方法,这次也是打算来一个全面深入的学习吧。知其然知其所以然,对于程序员还是蛮重要的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值