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很好的解决了多线程中,如 ...
随机推荐
- js 实现简单的parseInt和parseFloat
function myParseInt(str: string): number { let result = NaN; for (let i = 0; i < str.length; i++) ...
- js 动态构建style
使用创建style的方式 btn.addEventListener("click", async () => { const ns = document.createElem ...
- Ubuntu 下安装Anaconda + 显卡驱动 + CUDA + CUDNN + 离线安装环境
写来给自己备忘,并不是什么教程- .- 下载安装包 Anaconda:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 显卡驱动:https ...
- 【SVM】kaggle之澳大利亚天气预测
项目目标 由于大气运动极为复杂,影响天气的因素较多,而人们认识大气本身运动的能力极为有限,因此天气预报水平较低,预报员在预报实践中,每次预报的过程都极为复杂,需要综合分析,并预报各气象要素,比如温度. ...
- iOS拍个小视频
需求 公司混合开发,uni端拍小视频不是很理想,为达到仿微信效果,原生插件走起 思路 第1步:1个AVCaptureSession, 1块AVCaptureVideoPreviewLayer[考虑兼容 ...
- eclipse自定义快捷键
eclipse系统自带的快捷键设置有时候使用起来并不习惯,可以自定义某些常用的快捷键. 依次打开 Window->Preference->General->Keys,这里显示了所有的 ...
- ffmpeg番外篇:听说这款水印曾经在某音很火?办它!
今天在瞎逛时,偶然看到一个CSDN上的哥们说,他们曾经被一个水印难住了,仔细看了下,感觉可以用一行命令实现. 需求如下:视频加gif水印,gif循环,同时n秒后水印切换位置继续循环 这哥们遇到了两个问 ...
- springboot启动抛出javax.websocket.server.ServerContainer not available
问题描述:spring boot接入websocket时,启动报错:javax.websocket.server.ServerContainer not available <dependenc ...
- 后端程序员之路 18、朴素贝叶斯模型(Naive Bayesian Model,NBM)
贝叶斯推断及其互联网应用(一):定理简介 - 阮一峰的网络日志http://www.ruanyifeng.com/blog/2011/08/bayesian_inference_part_one.ht ...
- C#实现JWT无状态验证的实战应用
前言 本文主要介绍JWT的实战运用. 准备工作 首先我们创建一个Asp.Net的,包含MVC和WebApi的Web项目. 然后使用Nuget搜索JWT,安装JWT类库,如下图. 设计思路 这里我们简单 ...