一、阻塞队列

当阻塞队列是空,从队列中获取元素的操作会被阻塞

当阻塞队列是满,往队列中添加元素的操作会被阻塞

二、为什么用,有什么好处?

我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切阻塞队列都包办了。

三、常见的阻塞队列

ArrayBlockingQueue由数组构成的有界阻塞队列.

LinkedBlockingQueue由链表构成的有界阻塞队列(默认值为Integer.MAX_VALUE)

public class BlockingQueueDemo {

    public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(3);
/**
* 1、抛出异常 add()/remove()
*/
// System.out.println(blockingQueue.add("a"));
// System.out.println(blockingQueue.add("b"));
// System.out.println(blockingQueue.add("c"));
// System.out.println(blockingQueue.add("d")); // System.out.println(blockingQueue.element()); //检查队首元素 // System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove());
// System.out.println(blockingQueue.remove()); /**
* 2、返回布尔类型 offer()/pull()
*/
// System.out.println(blockingQueue.offer("a"));
// System.out.println(blockingQueue.offer("b"));
// System.out.println(blockingQueue.offer("c"));
// System.out.println(blockingQueue.offer("d"));
//
// System.out.println(blockingQueue.peek()); //检查队首元素
//
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll());
// System.out.println(blockingQueue.poll()); /**
* 3、阻塞 put()/take()
*/
// blockingQueue.put("a");
// blockingQueue.put("b");
// blockingQueue.put("c");
// System.out.println("############");
// blockingQueue.put("d");
//
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take());
// System.out.println(blockingQueue.take()); /**
*4、超时
*/ System.out.println(blockingQueue.offer("a",2L, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("b",2L, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("c",2L, TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("d",2L, TimeUnit.SECONDS));
}
}

SynchronousQueue是一个不存储元素的阻塞队列,也即单个元素的队列

public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>(); new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " put 1");
blockingQueue.put("1"); System.out.println(Thread.currentThread().getName() + " put 2");
blockingQueue.put("2"); System.out.println(Thread.currentThread().getName() + " put 3");
blockingQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "AAA").start(); new Thread(() -> {
try { TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take()); TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take()); TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + " take " + blockingQueue.take()); } catch (InterruptedException e) {
e.printStackTrace();
}
}, "BBB").start();
}
}  

PriorityBlockingQueue:支持优先级排序的无界阻塞队列

DelayQueue:使用优先级队列实现的延迟无界阻塞队列

LinkedTransferQueue:由链表构成的无界阻塞队列

LinkedBlockingDeque:由链表构成的双向阻塞队列

四、BlockQueue的核心方法

add()/remove()/element():抛出异常

offer()/pull():返回布尔类型/支持超时

put()/take():阻塞

peek() 检查队列首元素

五、使用场景

1、生产者-消费者模式

问题: 一个初始值为零的变量,两个线程对其交替操作,一个加1一个减1,来5轮

1)传统版的生产者-消费者模式

/**
* Created by wujuhong on 2019/7/3.
* 传统版的生产者消费者模式
*/
public class ProductConsumer_TraditionDemo { public static void main(String[] args) {
ShareData shareData = new ShareData();
new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
shareData.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "AA").start(); new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
shareData.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "BB").start();
}
} class ShareData {
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition(); public void increment() throws InterruptedException {
lock.lock();
try {
//1、判断
while (number != 0) {
//等待,不能生产
condition.await();
}
//2、干活
number++;
System.out.println(Thread.currentThread().getName() + " " + number);
//3、通知唤醒
condition.signalAll(); } finally {
lock.unlock();
}
} public void decrement() throws InterruptedException {
lock.lock();
try {
//1、判断
while (number == 0) {
//等待,不能生产
condition.await();
}
//2、干活
number--;
System.out.println(Thread.currentThread().getName() + " " + number);
//3、通知唤醒
condition.signalAll(); } finally {
lock.unlock();
}
}
}

  2)阻塞队列的生产者-消费者模式

class MyResource {
private volatile boolean FLAG = true; //默认生产,进行生产+消费
private AtomicInteger atomicInteger = new AtomicInteger();
BlockingQueue<String> blockingQueue = null; public MyResource(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
} public void myProduct() throws InterruptedException {
String data = "";
boolean returnValue;
while (FLAG) {
data = atomicInteger.incrementAndGet() + "";
returnValue = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
if (returnValue) {
System.out.println(Thread.currentThread().getName() + " 插入队列" + data + "成功");
} else {
System.out.println(Thread.currentThread().getName() + " 插入队列" + data + "失败"); }
TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName() + " 生产动作结束,FLAG = false");
} public void myConsume() throws InterruptedException {
String result = "";
while (FLAG) {
result = blockingQueue.poll(2, TimeUnit.SECONDS);
if (null == result || result.equalsIgnoreCase("")) {
FLAG = false;
System.out.println(Thread.currentThread().getName() + " 超过2s钟没有取到蛋糕,消费队列退出");
return; }
System.out.println(Thread.currentThread().getName() + " 消费队列" + result + "成功"); TimeUnit.SECONDS.sleep(1);
}
System.out.println(Thread.currentThread().getName() + " 消费动作结束,FLAG = false");
} public void stop() {
this.FLAG = false;
}
} public class ProductConsumer_BlockQueueDemo {
public static void main(String[] args) throws InterruptedException {
MyResource myResource = new MyResource(new ArrayBlockingQueue<String>(10));
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 生产线程启动");
try {
myResource.myProduct();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "product").start(); new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 消费线程启动");
try {
myResource.myConsume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "consume").start(); TimeUnit.SECONDS.sleep(5); System.out.println("5秒钟时间到,main线程叫停,活动结束"); myResource.stop();
}
}  

2、线程池

3、消息中间件

阻塞队列有没有好的一面?

不得不阻塞,你如何管理?

java面试-阻塞队列的更多相关文章

  1. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  2. Java集合--阻塞队列及各种实现的解析

    阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...

  3. Java:阻塞队列

    Java:阻塞队列 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. 概述 概念 队列 队列就可以想成是一个数组,从一头进入,一头出去,排队买饭 阻塞队列 B ...

  4. JAVA可阻塞队列-ArrayBlockingQueue

    在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...

  5. java 可伸缩阻塞队列实现

    最近一年多写的最虐心的代码.必须好好复习java并发了.搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励! import java.util.ArrayList; import java.util.L ...

  6. java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

    Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...

  7. Java -- 使用阻塞队列(BlockingQueue)控制线程通信

    BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...

  8. Java并发--阻塞队列

    在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...

  9. Java中阻塞队列的使用

    http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...

随机推荐

  1. JS Calendar API

    JS Calendar API js 如何获取当天是周几(一周的第几天) const date = new Date(); // Mon Mar 23 2020 15:15:36 GMT+0800 ( ...

  2. 微信附近的人,用redis也能实现?(GEO)

    相信微信附近的人的功能大家都应该用过 我可以很随意的通过我自己的定位能看到我附近的人,并且能看到那个人距离我的距离,大家有没有思考过这个是怎么实现的? 作为一个程序猿任何问题应该都有一个思考的过程,而 ...

  3. 执行Python程序时模块报错

    1. 在执行python程序时遇到 'ModuleNotFoundError: No module named 'xxxxx'' : 例如: 图片中以导入第三方的 'requests' 模块为例,此报 ...

  4. Java自学第9期——Lambda表达式

    1.入门 使用场景:如果创建函数式接口(该接口的抽象方法只能有一个)的实例时,使用Lambda表达式更加简洁方便. 2.格式: (形参列表) -> { 代码块 } 3.简化 只有一个参数时,可以 ...

  5. Java并发之CompletionService详解

    CompletionService是什么? 它是JUC包中的一个接口类,默认实现类只有一个ExecutorCompletionService. CompletionService干什么的? 它将异步任 ...

  6. vue项目配置 `webpack-obfuscator` 进行代码加密混淆

    背景 公司代码提供给第三方使用,为了不完全泄露源码,需要对给出的代码进行加密混淆,前端代码虽然无法做到完全加密混淆,但是通过使用 webpack-obfuscator 通过增加随机废代码段.字符编码转 ...

  7. Docker Elasticsearch 集群配置

    一:选用ES原因 公司项目有些mysql的表数据已经超过5百万了,各种业务的查询入库压力已经凸显出来,初步打算将一个月前的数据迁移到ES中,mysql的老数据就物理删除掉. 首先是ES使用起来比较方便 ...

  8. 一个基于 Vue3 的开源项目,3个月时间 star 终于破千!

    本文主要是对如何做开源项目的一些思考. 前文回顾: <Vue3 来了,Vue3 开源商城项目重构计划正式启动!> <一个基于 Vue 3 + Vant 3 的开源商城项目> 关 ...

  9. 一篇文章彻底弄懂Android-MVVM

    转: 一篇文章彻底弄懂Android-MVVM 在学习一个技术之前,我们首先要搞清为什么要用它.用它以后会有什么好处,这样我们才能有兴趣的学习下去. 一.为什么要用MVVM? 我为什么要用这个什么MV ...

  10. 腾讯一面问我SQL语句中where条件为什么写上1=1

    目录 where后面加"1=1″还是不加 不用where 1=1 在多条件查询的困惑 使用where 1=1 的好处 使用where 1=1 的坏处 where后面加"1=1″还是 ...