Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
作者:大飞
功能简介:
- ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列。队列中的元素遵循先入先出(FIFO)的规则。新元素插入到队列的尾部,从队列头部取出元素。
- 和普通队列有所不同,该队列支持阻塞操作。比如从空队列中取元素,会导致当前线程阻塞,直到其他线程将元素放入队列;将元素插入已经满的队列,同样会导致当前线程阻塞,直到其他线程从队列中取出元素。
- ArrayBlockingQueue也支持公平和非公平策略(针对队列中元素的存取线程,也可认为是元素的生产者和消费者)。
源码分析:
- ArrayBlockingQueue继承了AbstractQueue并实现了BlockingQueue,AbstractQueue是Queue的公共骨架实现,这个不看了,简单看下BlockingQueue接口:
public interface BlockingQueue<E> extends Queue<E> { /** * 将一个元素放入队列。 * 成功返回true;失败抛IllegalStateException异常。 */ boolean add(E e); /** * 将一个元素放入队列。 * 成功返回true;失败返回false。 */ boolean offer(E e); /** * 将一个元素放入队列。 * 如果元素无法放入队列,当前操作线程会等待,直到元素可以放入队列。 */ void put(E e) throws InterruptedException; /** * 将一个元素放入队列。 * 如果元素无法放入队列,当前操作线程会等待,直到元素可以放入队列或者 * 给定的时间超时。 * 成功返回true;超时返回false; */ boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; /** * 从队列头部获取并删除一个元素。 * 如果无法获取元素,当前操作线程等待,直到有元素可以被获取。 */ E take() throws InterruptedException; /** * 从队列头部获取并删除一个元素。 * 如果无法获取元素,当前操作线程等待,直到有元素可以被获取或者给定时间超时。 * 如果超时,返回null。 */ E poll(long timeout, TimeUnit unit) throws InterruptedException; /** * 获取队列剩余容量。 */ int remainingCapacity(); /** * 移除队列中和给定元素相同的元素。 */ boolean remove(Object o); /** * 判断队列中是否包含给定元素。 */ public boolean contains(Object o); /** * 移除队列中所有的可用元素,并把它们添加到给定集合。 */ int drainTo(Collection<? super E> c); /** * 移除队列中不超过给定数量的可用元素,并把它们添加到给定集合。 */ int drainTo(Collection<? super E> c, int maxElements); }
可以重点关注下put和take方法的行为。
- 接下来看下ArrayBlockingQueue内部的数据结构:
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { private static final long serialVersionUID = -817911632652898426L; /** 保存内部元素的数组 */ private final E[] items; /** 取元素使用的下标 */ private int takeIndex; /** 存元素使用的下标 */ private int putIndex; /** 队列中元素数量 */ private int count; /* * Concurrency control uses the classic two-condition algorithm * found in any textbook. */ /** 保护存取的锁 */ private final ReentrantLock lock; /** 取的等待条件 */ private final Condition notEmpty; /** 存的等待条件 */ private final Condition notFull; public ArrayBlockingQueue(int capacity) { this(capacity, false); } public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = (E[]) new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); } public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) { this(capacity, fair); if (capacity < c.size()) throw new IllegalArgumentException(); for (Iterator<? extends E> it = c.iterator(); it.hasNext();) add(it.next()); }
ArrayBlockingQueue内部结构非常简单,就是一个数组,一把锁,两个条件;也可以看到,上面提到的公平和非公平策略是由内部的重入锁来支持的。
- 继续看下ArrayBlockingQueue的重要方法,重点看下put和take,先看下put方法:
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); final E[] items = this.items; final ReentrantLock lock = this.lock; //由于需要支持方法可中断行为,这里使用可中断的锁操作。 lock.lockInterruptibly(); try { try { while (count == items.length) notFull.await();//队列满时,在notFull条件上等待。 } catch (InterruptedException ie) { notFull.signal(); // 被中断后,唤醒其他等待notFull条件的线程。 throw ie; } insert(e); } finally { lock.unlock(); } } /** * Circularly increment i. */ final int inc(int i) { return (++i == items.length)? 0 : i; } /** * 在内部数组的putIndex位置插入元素,调整putIndex和count,然后唤醒notEmpty条件上等待的线程。 * 本方法只有在持有锁的情况下才会被调用。 */ private void insert(E x) { items[putIndex] = x; putIndex = inc(putIndex); ++count; notEmpty.signal(); }
再看下take方法:
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { try { while (count == 0) notEmpty.await();//队列空时,在notEmpty条件上等待。 } catch (InterruptedException ie) { notEmpty.signal(); // 被中断后,唤醒其他等待notEmpty条件的线程。 throw ie; } E x = extract(); return x; } finally { lock.unlock(); } } /** * 从takeInde的位置取出元素,增加takeIndex,减少count,唤醒在notFull上等待的线程。 * 本方法只有在持有锁的情况下才会被调用。 */ private E extract() { final E[] items = this.items; E x = items[takeIndex]; items[takeIndex] = null; takeIndex = inc(takeIndex); --count; notFull.signal(); return x; }
- 其他方法的实现也都比较简单,不进行一一解析。最后注意一下,ArrayBlockingQueue的Iterator是弱一致的。
ArrayBlockingQueue的代码解析完毕!
相关推荐
Java并发包源码分析(JDK1.8):囊括了java.util.concurrent包中大部分类的源码分析,其中涉及automic包,locks包(AbstractQueuedSynchronizer、ReentrantLock、ReentrantReadWriteLock、LockSupport等),queue...
在Java世界中,JVM(Java Virtual Machine)和JUC(Java Concurrency Utilities)是两个极其重要的概念。JVM是Java程序的运行平台,而JUC则是Java并发编程的重要工具集。这个名为“JVM_JUC_Demo”的实践案例旨在帮助...
在JDK1.5及以后版本中,Java引入了Java并发工具包(java.util.concurrent,简称JUC),提供了一系列实用的并发编程类和接口。 2. **并发容器**: - 在示例中提到了`ArrayList`和`Vector`。`ArrayList`是非线程安全...
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
轻量级密码算法LBlock的FPGA优化实现.docx
街道级行政区划shp矢量数据,wgs84坐标系,下载直接使用
Git 资料 progit-zh-v2.1.1.pdf
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
篮球计分器FPGA附程序..doc
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
内容概要:本文档全面介绍了Linux开发的基础知识、应用场景、环境搭建、常用命令、Shell脚本编程以及C/C++和Python开发等内容。首先阐述了Linux开发的重要性及其在服务器端开发、嵌入式开发和系统运维等领域的广泛应用。接着详细讲解了如何选择合适的Linux发行版并安装系统,配置开发环境,包括安装必要的开发工具和配置SSH服务。文档还深入讲解了Linux基础命令,如文件和目录操作、文件内容查看与编辑、进程管理和权限管理。此外,介绍了Shell脚本编程的基本语法,包括变量、条件语句、循环语句和函数定义。针对C/C++和Python开发,文档分别讲解了编译器安装、程序编写与编译、调试方法及使用虚拟环境等内容。最后,简要介绍了Linux内核开发的相关知识,包括下载编译内核、内核模块开发等,并推荐了相关学习资源。 适合人群:对Linux开发感兴趣的初学者及有一定经验的研发人员,尤其是希望深入掌握Linux开发技能的开发者。 使用场景及目标:①掌握Linux开发环境的搭建与配置;②熟悉Linux基础命令和Shell脚本编程;③学习C/C++和Python在Linux下的开发流程;④了解Linux内核开发的基本概念和技术。 阅读建议:此文档内容丰富,涵盖面广,建议读者根据自身需求选择性阅读,并结合实际操作进行练习。特别是对于初学者,应先掌握基础命令和开发环境的搭建,再逐步深入到编程语言和内核开发的学习。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
街道级行政区划shp数据,wgs84坐标系,直接使用。
内容概要:本文档《word练习题.docx》是一份详细的Word操作练习指南,涵盖了从基础到高级的各种功能。文档分为三个主要部分:内容编辑、页面布局和高效文档。内容编辑部分包括文本格式化、段落设置、项目编号、制表位、边框与底纹等练习;页面布局部分涉及分节符、分栏、页眉页脚、水印等设置;高效文档部分则聚焦于样式管理、导航窗格、题注、书签、超级链接、脚注与尾注、交叉引用等功能。每个练习都有具体的操作步骤,帮助用户掌握Word的各种实用技巧。 适合人群:适用于Word初学者及希望提高Word技能的中级用户,尤其是需要频繁使用Word进行文档编辑和排版的办公人员。 使用场景及目标:①帮助用户熟悉Word的基本操作,如文本编辑、格式设置等;②提升用户的文档排版能力,学会设置复杂的页面布局;③提高工作效率,掌握高效文档管理技巧,如样式应用、题注和交叉引用等。 其他说明:此文档不仅提供了具体的练习题目,还附带了详细的步骤说明,用户可以根据指引逐步完成每个练习。此外,文档中的一些练习涉及到智能文档和Office智能客户端的应用,有助于用户了解Word在企业级应用中的潜力。建议用户按照章节顺序逐步学习,实践每一个练习,以达到最佳的学习效果。
街道级行政区划shp数据,wgs84坐标系,直接下载使用。
全球腐败感知数据(2000-2023)——3000行 33个指标 关于数据集 该数据集包含3000行和33列,涵盖了2000年至2023年的腐败感知指数(CPI)数据和各种治理指标。它包括国家排名、分数和其他指标,如公共部门腐败、司法腐败、贿赂指数、商业道德、民主指数、法治、政府效率、经济指标和人类发展指数。 这些数据可用于: 腐败趋势分析 腐败对GDP、人类发展指数和治理的影响 跨国比较 数据可视化和机器学习模型 该数据集对研究人员、数据分析师、政策制定者和对研究全球腐败趋势非常有用。