JUC——阻塞队列
Queue是一个队列,而队列的主要特征是FIFO先进先出,要实现生产者与消费者模型,也可以采用队列来进行中间的缓冲读取,好处是:生产者可以一直不停歇的生产数据。
BlockingQueue是Queue的子类,它实现有队列的基本特征:
public interface BlockingQueue<E> extends Queue<E>
在最初利用Queue实现生产者与消费者模型的时候发现一个问题:所有的消费者可能不是一个轮流操作,而是有可能某一个消费者长期进行消费处理。
阻塞队列
BlockingQueue通常用于一个线程生成对象,而另外一个线程消费这些对象的场景。

一个线程将会持续生成新对象并将其插入到队列之中,直到队列达到它所能容纳的临界点,也就是说,它是有限的。如果该阻塞队列到达了临界点,负责生产的线程将会再往里面插入新对象时发生阻塞。它会一直处于阻塞之中,直到负责消费的线程从队列中拿走一个对象。
BlockingQueue也是一个处理接口, 如果要想操作BlockingQueue也需要使用它的一系列子类:

对于阻塞队列而言最基础的两个实现子类:数组的队列,链表的队列。
范例:使用BlockingQueue实现一个消费者与生产者模型
package so.strong.mall.concurrent;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit; public class QueueDemo {
public static void main(String[] args) {
final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(5);//允许保存5个数据队列
for (int i = 0; i < 3; i++) { //3个生产者
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j++) {
try {
TimeUnit.SECONDS.sleep(j);
String str = "[生产数据{" + Thread.currentThread().getName() + "}] j = " + j;
queue.put(str); //会进入到生产的阻塞状态
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "生产者-" + i).start();
} for (int i = 0; i < 5; i++) { //5个消费者
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
if (queue.isEmpty()) { //队里内容为空
break;
}
System.out.println("[消费数据{" + Thread.currentThread().getName() + "}]" + queue.take());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "消费者-" + i).start(); }
}
}
除了数组之外也可以使用链表来进行操作:LinkedBlockingQueue。在使用这个类进行BlockingQueue接口对象实例化的时候,如果没有设置容量,则容量为:Integer.MAX_VALUE。
范例:修改为链表实现消费者与生产者模型
final BlockingQueue<String> queue = new LinkedBlockingQueue<>(5);//允许保存5个数据队列
链表是通过索引在进行弹出数据的,而链表只需要弹出第一个元素即可。
范例:采用优先级的PriorityBlockingQueue来实现数据操作
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable
PriorityBlockingQueue利用了Comparable接口来进行处理完成。
final BlockingQueue<String> queue = new PriorityBlockingQueue<>(5);//允许保存5个数据队列
对于使用哪一种具体的子类完全是由具体的开发环境来决定的。需要至少知道BlockingQueue这个阻塞队列核心就是提供有同步队列的功能。
SychronousQueue同步队列
之前使用的BlockingQueue每一次都可以保存多个数据对象信息,但是有些时候只能够允许保存一个数据的信息,这种情况下就要使用SychronousQueue子类来完成、
范例:使用同步队列来进行处理
package so.strong.mall.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit; public class QueueDemo {
public static void main(String[] args) {
final BlockingQueue<String> queue = new SynchronousQueue<>();//允许保存5个数据队列
for (int i = 0; i < 3; i++) { //3个生产者
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j++) {
try {
TimeUnit.SECONDS.sleep(j);
String str = "[生产数据{" + Thread.currentThread().getName() + "}] j = " + j;
queue.put(str); //会进入到生产的阻塞状态
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "生产者-" + i).start();
} for (int i = 0; i < 5; i++) { //5个消费者
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("[消费数据{" + Thread.currentThread().getName() + "}]" + queue.take());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "消费者-" + i).start();
}
}
}
现在不关心有多少个消费者与生产者,都采用一个接一个的形式执行。
BlockingDeque双端阻塞队列
BlockingQueue主要特征是只能够从一方面获取数据,也就是说它按照一个队列的形式采用了FIFO处理完成。但是现在希望可以按照前后各自处理,那么就需要BlocingDeque。
一个BlockingDeque线程在双端队列的两端都可以插入数据和提取数据。
一个线程生产元素,并把它们插入到队列的任意一端。如果双端队列已满,插入线程将被阻塞,直到一个移除线程从该队列中移除了一个元素。如果双端队列为空,移除线程将被阻塞,直到一个插入线程向该队列插入了一个新元素。

BlockingDeque接口结构:
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E>
子类LinkedBlockingDeque类结构
public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, java.io.Serializable
范例:观察双端队列的基本使用
package so.strong.mall.concurrent; import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit; /**
* @author Termis
* @date 2018/5/21
*/
public class QueueDemo {
public static void main(String[] args) {
final BlockingDeque<String> deque = new LinkedBlockingDeque<>();
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 5; j++) {
try {
TimeUnit.SECONDS.sleep(1);
String str;
if (j % 2 == 0) {
str = "[FIRST]生产数据{" + Thread.currentThread().getName() + "}y=" + j;
deque.addFirst(str);
} else {
str = "[LAST]生产数据{" + Thread.currentThread().getName() + "}y=" + j;
deque.addLast(str);
}
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "生产者-" + i).start();
} new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("[First]消费数据{" + Thread.currentThread().getName() + "}" + deque.takeFirst());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "消费者First").start(); new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("[Last]消费数据{" + Thread.currentThread().getName() + "}" + deque.takeLast());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "消费者Last").start(); }
}
生产者和消费者模型的实现方案很多。对于双端队列一定清楚它本身还是一个队列。如果现在first已经拽干净了,那么就继续拽last,就会有可能出现first消费last的情况。
public class QueueDemo {
    public static void main(String[] args) throws Exception {
        BlockingDeque<String> deque = new LinkedBlockingDeque<>();
        deque.addFirst("hello-first");
        deque.addFirst("world-first");
        deque.addLast("hello-last");
        deque.addLast("world-last");
        System.out.println(deque.takeFirst());
        System.out.println(deque.takeFirst());
        System.out.println(deque.takeFirst());
        System.out.println(deque.takeFirst());
    }
}
world-first
hello-first
hello-last
world-last
如果一端出现了阻塞,那么至少另外一端可以继续使用。
JUC——阻塞队列的更多相关文章
- java高并发系列 - 第25天:掌握JUC中的阻塞队列
		
这是java高并发系列第25篇文章. 环境:jdk1.8. 本文内容 掌握Queue.BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queu ...
 - java并发编程工具类JUC第一篇:BlockingQueue阻塞队列
		
Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一个可以存取元素,并且线程安全的队列.换句话说,当多线程同时从 JavaBlocking ...
 - JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑
		
直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列 public class JucPCdemo03 { /** * 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个 * ...
 - JUC之Java中的阻塞队列及其实现原理
		
在文章线程池实现原理 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中介绍了线程池的组成部分,其中一个组成部分就是阻塞队列.那么JAVA中的阻塞队列如何实现的呢? 阻塞队列,关键字是阻塞 ...
 - JUC组件扩展(三):BlockingQueue(阻塞队列)详解
		
一. 前言 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大 ...
 - 【JUC】阻塞队列&生产者和消费者
		
阻塞队列 线程1往阻塞队列添加元素[生产者] 线程2从阻塞队列取出元素[消费者] 当队列空时,获取元素的操作会被阻塞 当队列满时,添加元素的操作会被阻塞 阻塞队列的优势:在多线程领域,发生阻塞时,线程 ...
 - JUC 并发编程--10, 阻塞队列之--LinkedBlockingDeque  工作窃取, 代码演示
		
直接上代码 class LinkedBlockingDequeDemo { // 循环是否结束的开关 private static volatile boolean flag1 = true; pri ...
 - JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor
		
先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码: /** * 这个是 {@link DelayQueue} 延时队列 的验证使用类 */ class MyDelayed ...
 - JUC 并发编程--04  常用的辅助类CountDownLatch  ,  CyclicBarrier ,  Semaphore ,  读写锁 , 阻塞队列,CompletableFuture(异步回调)
		
CountDownLatch 相当于一个减法计数器, 构造方法指定一个数字,比如6, 一个线程执行一次,这个数字减1, 当变为0 的时候, await()方法,才开始往下执行,, 看这个例子 Cycl ...
 
随机推荐
- T-SQL 标识符
			
在T-SQL语言中,对SQLServer数据库及其数据对象(比如表.索引.视图.存储过程.触发器等)需要以名称来进行命名并加以区分,这些名称就称为标识符. 通常情况下,SQLServer数据库.数据库 ...
 - 【问题记录】python 函数 传入一个对象返回一个对象值得注意
			
写了一个函数,这个函数接收一个参数,在函数里面判断这个参数是否为None或者不合法状态, 如果处于不合法状态,则创建一个对象返回, 如果合法直接返回 代码示例如下: def get_mq_connec ...
 - python第三课——数据类型2
			
day03: 1.列表:list 特点:有序的(有索引.定义和显示顺序是一致的).可变的(既可以改变元素内容也可以自动扩容).可重复的. 可以存储任何的数据类型数据 定义个列表如下: lt = ['宋 ...
 - 1084. [SCOI2005]最大子矩阵【网格DP】
			
Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵 不能相互重叠. Input 第一行为n,m,k(1≤n≤100,1≤m≤ ...
 - 最长公共子序列&最长公共子串
			
首先区别最长公共子串和最长公共子序列 LCS(计算机科学算法:最长公共子序列)_百度百科 最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 最长公共子序列: http ...
 - 【node.js】函数、路由
			
Node.js中函数的使用与Javascript类似,一个函数可以作为另一个函数的参数.我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数. function say(word) { ...
 - mongodb启动与运用
			
在操作前需要启动mongodb数据库服务 1.首先打开dos窗口,然后选择路径到你的安装路径下的bin目录(我的路径是的D:mongo\mongodb\bin) 2.然后输入启动命令(D:mongo\ ...
 - Python之括号()[]{}
			
Python主要有三种数据类型:字典.列表.元组.其分别由花括号,中括号,小括号表示.如:字典:dic={'a':12,'b':34}列表:list=[1,2,3,4]元组:tup=(1,2,3,4)
 - 404 Note Found 队- BETA 版冲刺前准备
			
目录 过去存在的问题 任务分工 规范 后端总结 卉卉 家灿 前端总结 绪佩 青元 恺琳 宇恒 丹丹 算法&API接口 家伟 鸿杰 一好 文档&博客撰写 政演 产品功能 我们已经坐了哪些 ...
 - linux系统分析工具之Blktrace
			
Blktrace简介: blktrace是一个针对Linux内核中块设备I/O层的跟踪工具,用来收集磁盘IO信息中当IO进行到块设备层(block层,所以叫blk trace)时的详细信息(如IO请求 ...