并发库应用之十一 & 阻塞队列的应用
队列包含固定长度的队列和不固定长度的队列,队列的规则就是:先进先出。固定长度的队列往里放数据,如果放满了还要放,阻塞式队列就会等待,直到有数据取出,空出位置后才继续放;非阻塞式队列不能等待就只能报错了。
查看Condition的JDK文档时,其中简单的模拟实现了阻塞队列的原理,Java中也已经为我们提供了阻塞队列ArrayBlockingQueue,其定义如下:
public interface BlockingQueue<E> extends Queue<E>
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或 false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
抛出异常 | 特殊值 | 阻 塞 | 超 时 | |
插 入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移 除 | remove() | poll() | take() | poll(e, time, unit) |
检 查 | element() | peek() | 不可用 | 不可用 |
BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。
BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 附加元素。没有任何内部容量约束的 BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-消费者队列,但它另外还支持 Collection 接口。因此,举例来说,使用remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常不会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。
BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操作(addAll、containsAll、retainAll 和 removeAll)没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
java.util.concurrent.ArrayBlockingQueue<E> E--在此 collection 中保持的元素类型
extends AbstractQueue<E> implements BlockingQueue<E>, Serializable
一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。
这是一个典型的"有界缓存区",固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
此类支持对等待的生产者线程和消费者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
对应构造方法摘要:
ArrayBlockingQueue(int capacity) 创建一个带有给定的(固定)容量和默认访问策略的 ArrayBlockingQueue
ArrayBlockingQueue(int capacity, boolean fair) 创建一个具有给定的(固定)容量和指定访问策略的 ArrayBlockingQueue
ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c)
创建一个具有给定的(固定)容量和指定访问策略的 ArrayBlockingQueue,它最初包含给定 collection 的元素,并以 collection 迭代器的遍历顺序添加元素
方法摘要:
boolean add(E e) 将指定的元素插入此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则抛异常
void clear() 自动移除此队列中的所有元素
boolean contains(Object o) 如果此队列包含指定的元素,则返回 true
int drainTo(Collection<E> c) 移除此队列中所有可用的元素,并将它们添加到给定 collection 中
int drainTo(Collection<E> c, int maxElements) 最多从此队列中移除给定数量的可用元素,并将这些元素添加到给定 collection 中
......
这里我就不冗余多写这些方法的介绍了,有用到或者感兴趣的直接查文档即可。
阻塞队列与Semaphore有些相似,但也不同,阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一方设置和释放信号量。ArrayBlockingQueue只有put方法和take方法才具有阻塞功能,其他的不是得到一个指定的特殊值就是抛异常。
应用案例:
用3个空间的队列来演示阻塞队列的功能和效果。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; public class BlockingQueueTest {
public static void main(String[] args) {
//创建具有3个大小容量的阻塞队列
final BlockingQueue queue = new ArrayBlockingQueue(3);
for (int i = 0; i < 2; i++) { //分别启动3个写入和取出阻塞队列数据线程
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep((long) (Math.random() * 1000));
System.out.println(String.format("%s 准备放入队列数据...", Thread.currentThread().getName()));
queue.put(1);
System.out.println(String.format("%s 已经放了数据,队列目前有 %d 个数据", Thread.currentThread().getName(), queue.size()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
} new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(1000);
System.out.println(String.format("%s 准备从队列取数据...", Thread.currentThread().getName()));
queue.take();
System.out.println(String.format("%s 已经取走了数据,队列目前有 %d 个数据", Thread.currentThread().getName(), queue.size()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }.start();
}
}
以上代码运行打印效果如下:
提示:欢迎继续参看我相关的下一篇博客:并发库应用之十二 & 常用集合问题汇总
并发库应用之十一 & 阻塞队列的应用的更多相关文章
- Java多线程与并发库高级应用-可阻塞的队列
ArrayBlockQueue 可阻塞的队列 > 队列包含固定长度的队列和不固定长度的队列. > ArrayBlockQueue > 看BlockingQueue类的帮助文档,其中有 ...
- Java并发编程(十)阻塞队列
使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦.但是有了阻塞队列就不一样了, ...
- Java并发(7):阻塞队列
在前面我们接触的队列都是非阻塞队列,比如PriorityQueue.LinkedList(LinkedList是双向链表,它实现了Dequeue接口). 使用非阻塞队列的时候有一个很大问题就是:它不会 ...
- Java 并发系列之七:java 阻塞队列(7个)
1. 基本概念 2. 实现原理 3. ArrayBlockingQueue 4. LinkedBlockingQueue 5. LinkedBlockingDeque 6. PriorityBlock ...
- Java并发(基础知识)—— 阻塞队列和生产者消费者模式
1.阻塞队列 Blocki ...
- Java并发机制(6)--阻塞队列
Java并发编程:阻塞队列整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3933404.html 1.什么是阻塞队列 除了同步容器(Hashtable ...
- 并发库应用之十 & 多线程数据交换Exchanger应用
申明:用大白话来说就是用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人会一直等待第二个人,直到第二个人拿着数据到来时,才能彼此交换数据. java.util ...
- java并发之阻塞队列LinkedBlockingQueue与ArrayBlockingQueue
Java中阻塞队列接口BlockingQueue继承自Queue接口,并提供put.take阻塞方法.两个主要的阻塞类实现是ArrayBlockingQueue和LinkedBlockingQueue ...
- 转: 【Java并发编程】之二十一:并发新特性—阻塞队列和阻塞栈(含代码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17511147 阻塞队列 阻塞队列是Java5并发新特性中的内容,阻塞队列的接口是Java. ...
随机推荐
- 图像检索:CEDD(Color and Edge Directivity Descriptor)算法
颜色和边缘的方向性描述符(Color and Edge Directivity Descriptor,CEDD) 本文节选自论文<Android手机上图像分类技术的研究>. CEDD具有抽 ...
- The ENU localization is not supported by this SQL Server media
今儿在给服务器装sqlserver2008R2时遇到一个问题"The ENU localization is not supported by this SQL Server media&q ...
- CentOS 6.X启动流程
CentOS 6.X启动流程 /boot分区 启动引导程序是默认可以识别boot分区的.因此在系统还无法加载硬盘的时候,boot分区是可以识别的! initramfs内存文件系统 CentOS 6.x ...
- SpriteBuilder代码中弱引用(weak)需要注意的地方
比如在GameScene类中有一个弹出菜单层实例的引用,我们有: @implementation GameScene{ //other ivars __weak GameMenuLayer *_pop ...
- github搭建个人网站
1. 注册账号: 地址: https://github.com/ 输入账号.邮箱.密码,然后点击注册按钮. 2. 初始设置 注册完成后,选择Free免费账号完成设置. 2.1 验证邮箱 请打开你的 ...
- MVVM With ReactiveCocoa让移动开发更简单
作者:@雷纯锋2011 MVVM是一种软件架构模式,它是 Martin Fowler 的 Presentation Model 的一种变体,最先由微软的架构师 John Gossman 在 2005 ...
- 实现去哪儿来回机票选择的view
最近有个控件是实现和去哪儿和阿里旅行的app的选择日历效果,反编译没有效果的情况下我自己实现了个,大致的原理是: 上面是产品需要实现的效果,我看了下不就是一个ListView+gridView就能实现 ...
- SharePoint 2013配置开发环境,需安装VS2012插件
SharePoint 2013已经安装好了,接下来就是配置开发环境,安装VS2012,但是,装好了以后,发现没有SharePoint 2013开发的支持,如下图: 然后,去网上查找资料,VS2012对 ...
- Android studio 项目(Project)依赖(非Module)
Android studio 项目(Project)依赖(非Module) 0. 前言 对于Module 级别的依赖大家都知道,今天说下Android Studio下的项目依赖. 场景: A Proj ...
- sql server对并发的处理-乐观锁和悲观锁
https://www.cnblogs.com/dengshaojun/p/3955826.html sql server对并发的处理-乐观锁和悲观锁 假如两个线程同时修改数据库同一条记录,就会导致后 ...