加深一下BlockingQueue的认识
认识BlockingQueue
BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口。
add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常
offer:添加元素到队列里,添加成功返回true,添加失败返回false
put:添加元素到队列里,如果容量满了会阻塞直到容量不满
poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。
remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回false
take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除
参考文章 http://blog.csdn.net/x_i_y_u_e/article/details/52513038
认识一下ArrayBlockingQueue和LinkedBlockingQueue
这两个类是数组与链表的实现,这两个各有特点:
ArrayBlockingQueue
- 初始化时要指定长度
- 单个锁控制,读与写共用一个锁
- 基于array定位查找快
LinkedBlockingQueue
- 初始化时默认为Integer.MAX_VALUE
- 使用分离锁,写入时用的putLock,读取时用的takeLock
- 生产消息的时候需要转换为Node,有性能损耗
阻塞的原理
写时的阻塞
因为写入时阻塞主要是put方法,所以可以通过两个实现类的put方法来看一下是如何实现。
- ArrayBlockingQueue
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
可以看到这里会获取到一个锁,然后在在入队之前会有一个while,条件是count==item.length,其中count是指的当前队列已经写入的数据项个数,item是用于存数据的一个数组。也就是说如果当前队列的数据项等于数组的长度了,说明已经满了,此时则调用noteFull.await()阻塞当前线程;
- LinkedBlockingQueue
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
LinkedBlockingQueue在实现put时确实麻烦一些,只不过阻塞的模式是一样的,都是通过判断容易是否已经写满。
读时的阻塞
读时的配对方法是take,这个方法会对读取进行阻塞。
- LinkedBlockingQueue
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
可以看到原理一样,只不过这里用的是notEmpty这个条件对象,意思表示空的时候等待。
- LinkedBlockingQueue
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
同理LinkedBlockingQueue的实现也是一样的。
加深一下BlockingQueue的认识的更多相关文章
- Java多线程15:Queue、BlockingQueue以及利用BlockingQueue实现生产者/消费者模型
Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...
- 阅读ArrayBlockingQueue源码了解如何利用锁实现BlockingQueue
BlockingQueue是多线程里面一个非常重要的数据结构.在面试的时候,也常会被问到怎么实现BlockingQueue.本篇根据Java7里ArrayBlockingQueue的源码,简单介绍一下 ...
- BlockingQueue 阻塞队列,很有用的一种
BlockingQueue的核心方法:放入数据: offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳, 则返 ...
- BlockingQueue使用
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import ja ...
- [JAVA] BlockingQueue学习
有点时间,巩固巩固下基础知识:BlockingQueue,如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤 ...
- BlockingQueue深入分析(转)
1.BlockingQueue定义的常用方法如下 抛出异常 特殊值 阻塞 超时 插入 add(e) offer(e) put(e) offer(e,time,unit) 移除 remove() p ...
- 多线程编程-工具篇-BlockingQueue
在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全"传输"数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序 ...
- JAVA可阻塞队列-ArrayBlockingQueue子类BlockingQueue的应用,使用它来实现子线程打印10次,主线程打印100次,如此反复
/** * 使用BlockingQueue实现主子线程互相打印 * @author duwenlei * */ public class BlockingQueueTest { public stat ...
- [ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)
引言:PWM对于很多软件工程师可能又熟悉又陌生,以PWM调节LED亮度为例,其本质是在每个周期都偷工减料一些,整体表现出LED欠压亮度不同的效果.像大家看到的七色彩灯其原理也类似,只是用3路PWM分别 ...
随机推荐
- 关于textview显示特殊符号居中的问题
话说这是2017年的第一篇博客,也是一篇技术博客.先从简单的一篇解决问题开始吧,千里之行,始于足下! ------------------------------------------------- ...
- Logstash实践: 分布式系统的日志监控
文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...
- iOS二维码生成、识别、扫描等
二维码扫描 前言: 最近的项目中使用到了二维码,二维码这个模块功能也完成:觉得还是有必要总结一下用来做记录.好长时间没有写二维码了都忘记在差不多了,重新拾起来还是挻快的. 二维码使用场景: 生活中有很 ...
- 多个Img标签之间的间隙处理方法
1.多个标签写在一行 <img src="/i/eg_tulip.jpg" alt="郁金香" height="100px"/> ...
- iOS逆向工程之Reveal工具的安装、配置与使用
今天博客内容比较简单,不过还是蛮重要的.经常有小伙伴在QQ上私下问我,说博客中是如何使用Reveal查看AppStore中下载应用的UI层级的,那么就在今天这篇博客中作为一个主题来统一的介绍一下吧.虽 ...
- CGI与FastCGI nginx+PHP-FPM
本文转载自CGI与FastCGI 1.当我们在谈到cgi的时候,我们在讨论什么 最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html. ...
- “fixed+relative==absolute”——对BFC的再次思考
好久没写博客了,刚好今天跨年夜没约到什么妹子,在家宅着不如写点东西好了. 需求 昨天晚上,给公司年会做一个移动端的投票页面,遇到一个UI优化的问题: · 正文内容少于一屏时,投票提交按钮固定显示在页面 ...
- 记录一则Linux SSH的互信配置过程
需求:四台Linux主机,IP地址为192.168.10.10/11/12/13,配置登录用户的互信 1.各节点ssh-keygen生成RSA密钥和公钥 ssh-keygen -q -t rsa -N ...
- 我理解的MVC
前言 前一阶段对MVC模式及其衍生模式做了一番比较深入的研究和实践,这篇文章也算是一个阶段性的回顾和总结. 经典MVC模式 经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的 ...
- javascript 笔记!
1.通过javascript向文档中输出文本 document是javascript的内置对象,代表浏览器的文档部分 document.write("Hello Javascript&quo ...