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

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

学习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 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;
    }

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

总结

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

后续的阻塞队列实现呢,也了解差不多了,打算近期冲一波,多写点东西,免得日后懒癌发作又不肯动脑思考了。

说实话,每次学习这些源码,都觉得自己写的代码混乱不堪、毫无章法,既不优雅也没有任何深度,全是堆砌的业务代码,所以还需要不断学习顶尖程序员们的编程思路和代码结构吧。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5636702.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存