Java源码之阻塞队列
⑴背景
阻塞队列常用于生产者消费者场景,生产者是向队列里添加元素的线程,消费者是向队列里取出元素的线程。阻塞队列的角色是供生产者存放元素,消费者取出元素的容器。
⑵阻塞队列
阻塞队列是一个支持两个附加操作的队列。(支持阻塞插入和移除方法)
①阻塞插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满。
②阻塞移除:当队列空时,获取元素的线程会等待队列变为空。
/** The queued items */ final Object[] items; /** items index for next take, poll, peek or remove */ int takeIndex; /** items index for next put, offer, or add */ int putIndex; /** Number of elements in the queue */ int count; /* * Concurrency control uses the classic two-condition algorithm * found in any textbook. */ /** Main lock guarding all access */ final ReentrantLock lock; /** Condition for waiting takes */ private final Condition notEmpty; /** Condition for waiting puts */ private final Condition notFull;
/** * Creates an {@code ArrayBlockingQueue} with the given (fixed) * capacity and the specified access policy. * * @param capacity the capacity of this queue * @param fair if {@code true} then queue accesses for threads blocked * on insertion or removal, are processed in FIFO order; * if {@code false} the access order is unspecified. * @throws IllegalArgumentException if {@code capacity < 1} */ public ArrayBlockingQueue(int capacity, boolean fair) { //当队列容量小于等于0,会抛异常。当队列满时再继续插入,也会抛该异常 if (capacity <= 0) throw new IllegalArgumentException(); //创建容量数组 this.items = new Object[capacity]; //创建可重入锁与阻塞条件 lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); }
/** * Inserts the specified element at the tail of this queue, waiting * for space to become available if the queue is full. * * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; //lockInterruptibly()允许在等待时由其他线程的Thread.interrupt()方法来中断等待线程而直接返回,这时是不用获取锁的,而会抛出一个InterruptException。 //而ReentrantLock.lock()方法则不允许Thread.interrupt()中断,即使检测到了Thread.interruptted一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功之后在把当前线程置为interrupted状态。 lock.lockInterruptibly(); try { //当队列满时,阻塞插入队列的线程 while (count == items.length) notFull.await(); //对列不满就入队列 enqueue(e); } finally { //最后必须释放锁资源 lock.unlock(); } }
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; //加锁保证只有一个线程进入take方法 lock.lockInterruptibly(); try { //当队列为空时,阻塞取出元素的线程 while (count == 0) notEmpty.await(); //当队列队列非空时,允许元素加入队列 return dequeue(); } finally { lock.unlock(); } }
/** * Inserts element at current put position, advances, and signals. * Call only when holding lock. */ 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) //当索引等于数组最大值时,索引置0 putIndex = 0; count++; notEmpty.signal(); //使用条件对象notEmpty通知,当调用take,poll,remove时,线程被阻塞,对列为空,当调用enqueue时,队列不为空了,使用signal函数进行通知 }
/** * Extracts element at current take position, advances, and signals. * Call only when holding lock. */ private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); notFull.signal(); return x; }
该博客更详细,向博主学习,以后更深入学习后再来完善这篇博客。http://blog.csdn.net/x_i_y_u_e/article/details/52513038
Java源码之阻塞队列的更多相关文章
- 【Java源码】集合类-队列Queue
一.描述 队列Queue这种数据结构,通常指先进先出(FIFO)这种容器.可以模拟生活中依次排队这种场景. 下面是集合体系继承树: 二.Queue Queue和List一样都是Collection的子 ...
- Java并发编程:阻塞队列(转载)
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- 12、Java并发编程:阻塞队列
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- (转)Java并发编程:阻塞队列
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- 用Java如何设计一个阻塞队列,然后说说ArrayBlockingQueue和LinkedBlockingQueue
前言 用Java如何设计一个阻塞队列,这个问题是在面滴滴的时候被问到的.当时确实没回答好,只是说了用个List,然后消费者再用个死循环一直去监控list的是否有值,有值的话就处理List里面的内容.回 ...
- 【转】Java并发编程:阻塞队列
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- Java源码系列1——ArrayList
本文简单介绍了 ArrayList,并对扩容,添加,删除操作的源代码做分析.能力有限,欢迎指正. ArrayList是什么? ArrayList 就是数组列表,主要用来装载数据.底层实现是数组 Obj ...
- 【笔记0-开篇】面试官系统精讲Java源码及大厂真题
背景 开始阅读 Java 源码的契机,还是在第一年换工作的时候,被大厂的技术面虐的体无完肤,后来总结大厂的面试套路,发现很喜欢问 Java 底层实现,即 Java 源码,于是我花了半年时间,啃下了 J ...
- [源码解析] 消息队列 Kombu 之 基本架构
[源码解析] 消息队列 Kombu 之 基本架构 目录 [源码解析] 消息队列 Kombu 之 基本架构 0x00 摘要 0x01 AMQP 1.1 基本概念 1.2 工作过程 0x02 Poll系列 ...
随机推荐
- 1. 全文搜索框架 Haystack
1.什么是Haystack Haystack是django的开源全文搜索框架(全文检索不同于特定字段的模糊查询,使用全文检索的效率更高 ),该框架支持Solr,Elasticsearch,Whoosh ...
- .Net Core 创建和使用中间件
1. 定义中间内容 1.1 必须有一个RequestDelegate 委托用了进入一个中间件 1.2 通过构造函数设置这个RequestDelegate委托 1.3 必须有一个方法Task Invok ...
- springboot不同环境打包
1. 场景描述 springboot+maven打包,项目中经常用到不同的环境下打包不同的配置文件,比如连接的数据库.配置文件.日志文件级别等都不一样. 2. 解决方案 在pom.xml文件中定义 2 ...
- 文件传输——TCP/IP协议介绍总结
一.链路层 数据链路层的工作特性: 1.为IP模块发送和接收IP数据报2.为ARP模块发送ARP请求和接收ARP应答(ARP:地址解析协议,将IP地址转换成MAC地址)3.为RARP发送RARP请求和 ...
- python函数知识四 迭代器、生成器
15.迭代器:工具 1.可迭代对象: 官方声明,只要具有__iter__方法的就是可迭代对象 list,dict,str,set,tuple -- 可迭代对象,使用灵活 #方法一: list.__ ...
- c++小游戏——彩票
#include <cstdlib> #include <iostream> #include <cstdio> #include <cmath> #i ...
- python 中_init_函数以及参数self
1)class类包含: 类的属性:类中所涉及的变量 类的方法:类中函数 2)_init_函数(方法) 1.首先说一下,带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问. 2. ...
- 个人永久性免费-Excel催化剂功能第22波-Excel文件类型、密码批量修改,补齐PowerQuery短板
Excel的多工作薄.多工作表批量合并功能,Excel用户很多这方面的使用场景,也促使了各大Excel各大插件们都在此功能上有所开发,体验程度不一,但总体能够满足大多数的应用场景,本人之前也开发个单独 ...
- 小白开学Asp.Net Core 《九》
小白开学Asp.Net Core <九> — — 前端篇(不务正业) 在<小白开学Asp.Net Core 三>中使用了X-admin 2.x 和 Layui将管理后端的界面重 ...
- 什么是icmp协议?
英文原义:Internet Control Message Protocol 中文释义:(RFC-792)Internet控制消息协议 定义: ICMP协议是一种面向无连接的协议,用于传输出 ...