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——阻塞队列的更多相关文章

  1. java高并发系列 - 第25天:掌握JUC中的阻塞队列

    这是java高并发系列第25篇文章. 环境:jdk1.8. 本文内容 掌握Queue.BlockingQueue接口中常用的方法 介绍6中阻塞队列,及相关场景示例 重点掌握4种常用的阻塞队列 Queu ...

  2. java并发编程工具类JUC第一篇:BlockingQueue阻塞队列

    Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一个可以存取元素,并且线程安全的队列.换句话说,当多线程同时从 JavaBlocking ...

  3. JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑

    直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列 public class JucPCdemo03 { /** * 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个 * ...

  4. JUC之Java中的阻塞队列及其实现原理

    在文章线程池实现原理 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中介绍了线程池的组成部分,其中一个组成部分就是阻塞队列.那么JAVA中的阻塞队列如何实现的呢? 阻塞队列,关键字是阻塞 ...

  5. JUC组件扩展(三):BlockingQueue(阻塞队列)详解

    一. 前言 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大 ...

  6. 【JUC】阻塞队列&生产者和消费者

    阻塞队列 线程1往阻塞队列添加元素[生产者] 线程2从阻塞队列取出元素[消费者] 当队列空时,获取元素的操作会被阻塞 当队列满时,添加元素的操作会被阻塞 阻塞队列的优势:在多线程领域,发生阻塞时,线程 ...

  7. JUC 并发编程--10, 阻塞队列之--LinkedBlockingDeque 工作窃取, 代码演示

    直接上代码 class LinkedBlockingDequeDemo { // 循环是否结束的开关 private static volatile boolean flag1 = true; pri ...

  8. JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor

    先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码: /** * 这个是 {@link DelayQueue} 延时队列 的验证使用类 */ class MyDelayed ...

  9. JUC 并发编程--04 常用的辅助类CountDownLatch , CyclicBarrier , Semaphore , 读写锁 , 阻塞队列,CompletableFuture(异步回调)

    CountDownLatch 相当于一个减法计数器, 构造方法指定一个数字,比如6, 一个线程执行一次,这个数字减1, 当变为0 的时候, await()方法,才开始往下执行,, 看这个例子 Cycl ...

随机推荐

  1. php解析xml文件的方法

    最近一段时间在做模板包导入.模板包中包含有xml文件,,需要解析成给定的php数组格式. 我接触到了两种方法,分别是DOMDocument 方法和 simple_load_file. 个人偏好后一种, ...

  2. shell批量远程连接mysql的方法

    一.配置mysql服务器ip列表如下,可自定义: S1     1.1.1.1     3306 user passwd11   dbname_s1S2      2.2.2.2     3306 u ...

  3. Spring-IOC BeanFactory运行时动态注册bean

    在spring运行时,动态的添加bean,dapeng框架在解析xml的字段时,使用到了动态注册,注册了一个实现了FactoryBean类! 定义一个没有被Spring管理的Controller pu ...

  4. [AHOI2009]飞行棋

    嘟嘟嘟 刚开始想这道题的时候确实很蒙,只想到矩形对边做对应的弧长相等,然后想办法凑出相等的弧长.其实正解很简单,不要去想边,应该想对角线,因为根据初中园的知识,这个矩形的对角线是圆的直径,而直径所对的 ...

  5. 20155314 2016-2017-2 《Java程序设计》第1周学习总结

    20155314 2016-2017-2 <Java程序设计>第1周学习总结 学习目标 了解Java基础知识(已完成) 了解JVM.JRE与JDK,并下载.安装.测试JDK(已完成) 了解 ...

  6. [转]DirectX and .NET[英]

    With the DirectX SDK (June 2010) release and the addition of support for Visual Studio 2010, I’ve be ...

  7. mapent

    package test12; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import ja ...

  8. maven3 下载列表

    https://archive.apache.org/dist/maven/maven-3/ Parent Directory - 3.0.4/ 2012-09-11 09:37 - 3.0.5/ 2 ...

  9. 再起航,我的学习笔记之JavaScript设计模式07(抽象工厂模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前两 ...

  10. HDU 1251 统计难题(字典树入门模板题 很重要)

    统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131070/65535 K (Java/Others)Total Submi ...