java面试-阻塞队列
一、阻塞队列
当阻塞队列是空,从队列中获取元素的操作会被阻塞
当阻塞队列是满,往队列中添加元素的操作会被阻塞
二、为什么用,有什么好处?
我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切阻塞队列都包办了。
三、常见的阻塞队列
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面试-阻塞队列的更多相关文章
- Java多线程 阻塞队列和并发集合
转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...
- Java集合--阻塞队列及各种实现的解析
阻塞队列(Blocking Queue) 一.队列的定义 说的阻塞队列,就先了解下什么是队列,队列也是一种特殊的线性表结构,在线性表的基础上加了一条限制:那就是一端入队列,一端出队列,且需要遵循FIF ...
- Java:阻塞队列
Java:阻塞队列 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. 概述 概念 队列 队列就可以想成是一个数组,从一头进入,一头出去,排队买饭 阻塞队列 B ...
- JAVA可阻塞队列-ArrayBlockingQueue
在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...
- java 可伸缩阻塞队列实现
最近一年多写的最虐心的代码.必须好好复习java并发了.搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励! import java.util.ArrayList; import java.util.L ...
- java 多线程阻塞队列 与 阻塞方法与和非阻塞方法
Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移 ...
- Java -- 使用阻塞队列(BlockingQueue)控制线程通信
BlockingQueeu接口是Queue的子接口,但是它的主要作用并不是作为容器,而是作为线程同步的工具. 特征: 当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程 ...
- Java并发--阻塞队列
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- Java中阻塞队列的使用
http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如 ...
随机推荐
- how to change svg polygon size by update it's points in js
how to change svg polygon size by update it's points in js matrixTransform https://stackoverflow.com ...
- PAUL ADAMS ARCHITECT:薪资追不上房价美一半家庭难买房
尽管上一年度美国经济遭受重创,但美国房价依旧持续蹿扬,据最新调查显示,美国大部分地区的房价已经到了一般家庭无法负担的水准. 美国房价上涨持续强劲,主要受益美国人居家办公需求(受大环境影响,目前美国有7 ...
- 人物传记Kyle Tedford:数据环境生变,银行大数据风控怎么办?
数据是金融业务的基石,监管集中清查大数据公司,很多东西在发生根本性改变,资金方做"甩手掌柜"的好日子不会重现.那些缺乏自主风控能力的金融机构,在未来的行业竞争中,恐无以立足了.近日 ...
- Windows Server2012 r2 nginx反向代理图片服务器
1.下载nginx http://nginx.org/en/download.html,本人下载的1.18.0版本 2.下载 Windows Service Wrapper(winsw.exe) v ...
- 内核栈与thread_info结构详解
本文转载自内核栈与thread_info结构详解 什么是进程的内核栈? 在内核态(比如应用进程执行系统调用)时,进程运行需要自己的堆栈信息(不是原用户空间中的栈),而是使用内核空间中的栈,这个栈就是进 ...
- Redis 日志篇:系统高可用的杀手锏
特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...
- 换人!golang面试官:连怎么避免内存逃逸都不知道?
问题 怎么避免内存逃逸? 怎么答 在runtime/stubs.go:133有个函数叫noescape.noescape可以在逃逸分析中隐藏一个指针.让这个指针在逃逸分析中不会被检测为逃逸. // n ...
- hive复杂数据类型的用法
目录 1.简单描述 2.测试 1.简单描述 arrays: ARRAY<data_type> maps: MAP<primitive_type, data_type> stru ...
- redis.conf 配置说明
redis.conf 配置项说明如下: 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时,R ...
- Element 文档中的 Markdown 解析
Element 的文档站是讲Markdown解析成vue组件在页面中渲染出来,转换过程如下图所示: 红框部分势必要对 Markdown 进行特殊的订制,订制过的 Markdown 像下面这样. ::: ...