Java多线程(五)之BlockingQueue深入分析
一、概述:
二、BlockingQueue定义的常用方法
1.BlockingQueue定义的常用方法如下:

1.1 添加新元素的方法:add/put/offer
首先,谈到添加元素的方法,首先得分析以下该类同步机制中用到的锁:
Java代码
- lock = new ReentrantLock(fair);
- notEmpty = lock.newCondition();//Condition Variable 1
- notFull = lock.newCondition();//Condition Variable 2
这三个都是该类的实例变量,只有一个锁lock,然后lock实例化出两个Condition,notEmpty/noFull分别用来协调多线程的读写操作。
Java代码
- public boolean offer(E e) {
- if (e == null) throw new NullPointerException();
- final ReentrantLock lock = this.lock;//每个对象对应一个显示的锁
- lock.lock();//请求锁直到获得锁(不可以被interrupte)
- try {
- if (count == items.length)//如果队列已经满了
- return false;
- else {
- insert(e);
- return true;
- }
- } finally {
- lock.unlock();//
- }
- }
- 看insert方法:
- private void insert(E x) {
- items[putIndex] = x;
- //增加全局index的值。
- /*
- Inc方法体内部:
- final int inc(int i) {
- return (++i == items.length)? 0 : i;
- }
- 这里可以看出ArrayBlockingQueue采用从前到后向内部数组插入的方式插入新元素的。如果插完了,putIndex可能重新变为0(在已经执行了移除操作的前提下,否则在之前的判断中队列为满)
- */
- putIndex = inc(putIndex);
- ++count;
- notEmpty.signal();//wake up one waiting thread
- }
Java代码
- 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();//请求锁直到得到锁或者变为interrupted
- try {
- try {
- while (count == items.length)//如果满了,当前线程进入noFull对应的等waiting状态
- notFull.await();
- } catch (InterruptedException ie) {
- notFull.signal(); // propagate to non-interrupted thread
- throw ie;
- }
- insert(e);
- } finally {
- lock.unlock();
- }
- }
Java代码
- public boolean offer(E e, long timeout, TimeUnit unit)
- throws InterruptedException {
- if (e == null) throw new NullPointerException();
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.lock;
- lock.lockInterruptibly();
- try {
- for (;;) {
- if (count != items.length) {
- insert(e);
- return true;
- }
- if (nanos <= 0)
- return false;
- try {
- //如果没有被 signal/interruptes,需要等待nanos时间才返回
- nanos = notFull.awaitNanos(nanos);
- } catch (InterruptedException ie) {
- notFull.signal(); // propagate to non-interrupted thread
- throw ie;
- }
- }
- } finally {
- lock.unlock();
- }
- }
Java代码
- public boolean add(E e) {
- return super.add(e);
- }
- 父类:
- public boolean add(E e) {
- if (offer(e))
- return true;
- else
- throw new IllegalStateException("Queue full");
- }
1.2 该类的几个实例变量:takeIndex/putIndex/count
Java代码
- 用三个数字来维护这个队列中的数据变更:
- /** items index for next take, poll or remove */
- private int takeIndex;
- /** items index for next put, offer, or add. */
- private int putIndex;
- /** Number of items in the queue */
- private int count;
提取元素的三个方法take/poll/remove内部都调用了这个方法:
Java代码
- private E extract() {
- final E[] items = this.items;
- E x = items[takeIndex];
- items[takeIndex] = null;//移除已经被提取出的元素
- takeIndex = inc(takeIndex);//策略和添加元素时相同
- --count;
- notFull.signal();//提醒其他在notFull这个Condition上waiting的线程可以尝试工作了
- return x;
- }
从这个方法里可见,tabkeIndex维护一个可以提取/移除元素的索引位置,因为takeIndex是从0递增的,所以这个类是FIFO队列。
putIndex维护一个可以插入的元素的位置索引。
count显然是维护队列中已经存在的元素总数。
arg)方法来判定,并且享受ReentranLock的重进入特性。
- public final void await() throws InterruptedException {
- if (Thread.interrupted())
- throw new InterruptedException();
- //加一个新的condition等待节点
- Node node = addConditionWaiter();
- //释放自己的锁
- int savedState = fullyRelease(node);
- int interruptMode = 0;
- while (!isOnSyncQueue(node)) {
- //如果当前线程 等待状态时CONDITION,park住当前线程,等待condition的signal来解除
- LockSupport.park(this);
- if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
- break;
- }
- if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
- interruptMode = REINTERRUPT;
- if (node.nextWaiter != null)
- unlinkCancelledWaiters();
- if (interruptMode != 0)
- reportInterruptAfterWait(interruptMode);
- }
是尝试添加到队列中的首个已排队线程元素;如果没有已排队线程,则不添加元素并且头为 null。对于其他Collection 方法(例如 contains),SynchronousQueue 作为一个空集合。此队列不允许 null 元素。
queue。此队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
- private final PriorityQueue q;
- private final ReentrantLock lock = new ReentrantLock(true);
- private final Condition notEmpty = lock.newCondition();
expired furthest in the past. If no delay has expired there is no head and poll will returnnull. Expiration occurs when an element's getDelay(TimeUnit.NANOSECONDS) method returns a value less than or equal to zero. Even though unexpired elements cannot be
removed using take or poll, they are otherwise treated as normal elements. For example, the size method returns the count of both expired and unexpired elements. This queue does not permit null elements.

Java多线程(五)之BlockingQueue深入分析的更多相关文章
- Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock
在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...
- java多线程(五)之总结(转)
引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个 ...
- Java多线程系列十——BlockingQueue
参考资料:http://ifeve.com/java-synchronousqueue/http://www.cnblogs.com/jackyuj/archive/2010/11/24/188655 ...
- java多线程(五)-访问共享资源以及加锁机制(synchronized,lock,voliate)
对于单线程的顺序编程而言,每次只做一件事情,其享有的资源不会产生什么冲突,但是对于多线程编程,这就是一个重要问题了,比如打印机的打印工作,如果两个线程都同时进行打印工作,那这就会产生混乱了.再比如说, ...
- Java多线程-工具篇-BlockingQueue(转)
前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列 类,为我们快速搭建高质量的多线程程序带来极大的 ...
- [Java基础] Java多线程-工具篇-BlockingQueue
转载自: http://www.cnblogs.com/jackyuj/archive/2010/11/24/1886553.html 前言: 在新增的Concurrent包中,BlockingQue ...
- Java多线程-工具篇-BlockingQueue
前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列 类,为我们快速搭建高质量的多线程程序带来极大的 ...
- Java 多线程(五)之 synchronized 的使用
目录 1 线程安全 2 互斥锁 3 内置锁 synchronized 3.1 普通同步方法,锁是当前实例对象(this) 3.1.1 验证普通方法中的锁的对象是同一个. 3.1.2 验证不同的对象普通 ...
- Java多线程(五) —— 线程并发库之锁机制
参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...
- Java多线程——<五>后台线程(daemon)
一.后台线程(守护线程) 学一个东西,最重要的一点就是,为什么要用它? 后台线程区别于普通线程,普通线程又可以称为用户线程,只完成用户自己想要完成的任务,不提供公共服务.而有时,我们希望编写一段程序, ...
随机推荐
- AutoCAD2016简体中文破解版32位64位下载
AutoCAD2016序列号:666-69696969 667-98989898 400-45454545 066-66666666(任意一个) AutoCAD2016产品密钥:001H1 AutoC ...
- 剑指offer---1、顺时针打印矩阵
剑指offer---1.顺时针打印矩阵 一.总结 一句话总结: 谋而后动+多做:还是要谋而后动,但是怎么谋而后动,很有学问,做好的方式就是多做 问题就这些问题:解决了就好了,比如php多维数组 面试的 ...
- 二:unittest框架配合selenium之xpath定位
刚开始学习selenium自动化测试时,犯了一个不该犯的错误,偷懒,使用火狐浏览器中的扩展FIREBUG,FIREPATH来辅助定位. 虽然用的定位方法大多数是使用XPATH方法,但是是工具定位出来的 ...
- 搭建单机版spark
二.下载软件 JDK,Scala,SBT,Maven 版本信息如下: JDK jdk-7u79-linux-x64.gz Scala scala-2.10.5.tgz 三.解压上述文件并进行环境变量配 ...
- 20、formAdd,javascript实现动态添加
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- SQL Server2012 安装方法详解
SQL Server2012 安装方法详解 - MonkeyBrothers的博客 - CSDN博客 https://blog.csdn.net/monkeybrothers/article/deta ...
- 什么是CI/CD?
CI, CD AND CD 当我们在谈论现代的软件编译和发布流程的时候,经常会听到CI 和CD这样的缩写短语.CI很容易理解,就是持续集成.但是CD既可以指代码持续交付,也可理解为代码持续部署.CI和 ...
- kafka相关业务必会操作命令整理
参考:https://kafka.apache.org 服务相关命令 1.启动/停止zk > bin/zookeeper-server-start.sh config/zookeeper.pro ...
- C# WinfForm 控件之dev图表 ChartControl
dev 图表控件 学习连接 新建一个winformApp form1上放一个button 再放一个chartControl Name 为cct 直接上代码 private void button1_C ...
- Mysql的Event
Mysql的Event Event简介 Event是mysql中的一个事件,和触发器类似,触发器是在某条sql语句执行后可能会触发,而Event是每隔一段时间或某个特定的时间点执行,可以精确到秒. 准 ...