JUC并发编程学习笔记(九)阻塞队列
阻塞队列
阻塞
队列
队列的特性:FIFO(fist inpupt fist output)先进先出
不得不阻塞的情况




什么情况下会使用阻塞队列:多线程并发处理、线程池
学会使用队列
添加、移除
四组API
| 方式 | 抛出异常 | 不抛出异常,有返回值 | 阻塞等待 | 超时等待 |
|---|---|---|---|---|
| 添加 | add | offer | put | offer(E e, long timeout, TimeUnit unit) |
| 移除 | remove | poll | take | poll(long timeout, TimeUnit unit) |
| 检测队首元素 | element | peek |
1、抛出异常
public static void test01(){
//队列是有大小的,创建时要明确该队列最大能有几个元素
BlockingQueue queue = new ArrayBlockingQueue<>(3);
//当你添加的元素超出队列规定的最大元素量时,抛出异常java.lang.IllegalStateException: Queue full
System.out.println(queue.add("A"));
System.out.println(queue.add("B"));
System.out.println(queue.add("C"));
//当你移除的元素超出队列中含有的元素量时,抛出异常java.util.NoSuchElementException
System.out.println(queue.element());
System.out.println(queue.remove());
System.out.println(queue.element());
System.out.println(queue.remove());
System.out.println(queue.element());
System.out.println(queue.remove());
System.out.println(queue.add("D"));
}
2、不抛出异常
public static void test02(){
//队列是有大小的,创建时要明确该队列最大能有几个元素
BlockingQueue queue = new ArrayBlockingQueue<>(3);
//当你添加的元素超出队列规定的最大元素量时,不抛出异常,通过返回的boolean值为false来表明
System.out.println(queue.offer("A"));
System.out.println(queue.offer("B"));
System.out.println(queue.offer("C"));
//当你移除的元素超出队列中含有的元素量时,不抛出异常,返回null来提示队列已经没有元素可以弹出了
System.out.println(queue.peek());
System.out.println(queue.poll());
System.out.println(queue.peek());
System.out.println(queue.poll());
System.out.println(queue.peek());
System.out.println(queue.poll());
System.out.println(queue.offer("D"));
}
3、阻塞等待
public static void test03() throws InterruptedException {
//队列是有大小的,创建时要明确该队列最大能有几个元素
BlockingQueue queue = new ArrayBlockingQueue<>(3);
queue.put("a");
queue.put("b");
queue.put("c");
//当队列被元素占满后再进行添加,会一直阻塞等待,知道该元素加入队列
// queue.put("c");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
//当队列中没有元素时还去取,也会一直阻塞等待
// System.out.println(queue.take());
}
4、超时等待
public static void test04() throws Exception{
//队列是有大小的,创建时要明确该队列最大能有几个元素
BlockingQueue queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
//当队列被占满时,设置超时等待,超过两秒就不等了,进不去就不进了
System.out.println(queue.offer("d", 2, TimeUnit.SECONDS));
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
//当队列元素为空时,设置超时等待,超过两秒就不等了,拿不到就不拿了
System.out.println(queue.poll(2, TimeUnit.SECONDS));
}
SynchronousQueue
同步队列:同步队列每次插入操作都必须等待另一个线程执行相应的删除操作,反之亦然。同步队列没有容量,也就意味着只有当一个元素弹出后才能再进入一个元素,只能同时有一个元素。

存取:put、take
package org.example.qu;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue<String> synchroQueue = new SynchronousQueue<String>();
new Thread(() -> {
try {
//直接在队列中存入三个元素
System.out.println(Thread.currentThread().getName() + ": put 1");
synchroQueue.put("1");
System.out.println(Thread.currentThread().getName() + ": put 2");
synchroQueue.put("2");
System.out.println(Thread.currentThread().getName() + ": put 3");
synchroQueue.put("3");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "T1").start();
new Thread(() -> {
try {
//每次取之间延迟三秒
TimeUnit.SECONDS.sleep(3);
System.out.println(synchroQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(synchroQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(synchroQueue.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "T2").start();
}
}
我们通过结果发现,将要存入的元素会等待已经被存入的元素取出后才会存入,延迟三秒取出时,将要存入的元素也在等待三秒取出后再存入,这就是所谓的同步队列每次插入操作都必须等待另一个线程执行相应的删除操作,反之亦然。
同步队列和其它BlockingQueue不一样,他不存储元素,你put了一个值必须take取出,否则不能再put进去元素。
JUC并发编程学习笔记(九)阻塞队列的更多相关文章
- JUC并发编程学习笔记
JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...
- Java 并发编程学习笔记 理解CLH队列锁算法
CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁.结点之间是通过隐形的链表相连,之所以叫隐形的链 ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
- 并发编程学习笔记(5)----AbstractQueuedSynchronizer(AQS)原理及使用
(一)什么是AQS? 阅读java文档可以知道,AbstractQueuedSynchronizer是实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量.事件,等等)提供一个框架, ...
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- 并发编程学习笔记(15)----Executor框架的使用
Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...
- 并发编程学习笔记(11)----FutureTask的使用及实现
1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...
- 并发编程学习笔记(12)----Fork/Join框架
1. Fork/Join 的概念 Fork指的是将系统进程分成多个执行分支(线程),Join即是等待,当fork()方法创建了多个线程之后,需要等待这些分支执行完毕之后,才能得到最终的结果,因此joi ...
- 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理
在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...
随机推荐
- ListView选中获取数据并弹出菜单项
前言 作为一名Android小白,我在编写过程中,使用ListView列表,想要使用他来完成长按弹出菜单选项,并且还要进行事件操作,经过百度编程的经历后,终于成功完成.在此附上这块比较完整的代码,理论 ...
- 【MAUI Blazor踩坑日记】2.关于Windows上的相机问题
前言 本系列文章,默认你已经踏上了MAUI Blazor的贼船,并且对MAUI Blazor有了一些了解,知道MAUI是什么,知道Blazor是什么. 不会教你怎么写MAUI Blazor的项目,只是 ...
- 您在 /var/spool/mail/root 中有新邮件
查看邮件 删除邮件 禁止系统启动邮件检查这样就再有邮件提示了 mail cat /dev/null > /var/spool/mail/root echo "unset MAILCHE ...
- [etcd]基本数据库操作
前言 etcd数据库操作基本围绕着对键值和目录的CRUD操作,以及生命周期的管理. 之前在单节点部署了三实例集群,而etcdctl默认找的是127.0.0.1:2379,所以这里先声明一个临时全局变量 ...
- Robot 框架学习笔记
Robot 框架学习笔记 为了更好地让读者理解快速学习新框架的思路,笔者接下来会继续介绍另一个名为 Robot 的自动化测试框架,希望读者能参考笔者从零开始讲解一个开发/测试框架的流程,从中总结出适合 ...
- 文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题
六.如果用go语言,考虑对 PARTITION 过程做这样的修改:从数组 A 中随机选出三个元素,并用这三个元素的中位数(即这三个元素按大小排在中间的值)对数组进行划分.求以a 的函数形式表示的.最坏 ...
- Redis从入门到放弃(11):雪崩、击穿、穿透
1.前言 Redis作为一款高性能的缓存数据库,为许多应用提供了快速的数据访问和存储能力.然而,在使用Redis时,我们不可避免地会面对一些常见的问题,如缓存雪崩.缓存穿透和缓存击穿.本文将深入探讨这 ...
- 详谈 springboot整合shiro
背景: 上文学习了shrio 基本概念后,本章将进一步的落地实践学习,在springboot中如何去整合shrio,整个过程步骤有个清晰的了解. 利用Shiro进行登录认证主要步骤: 1. 添加依赖: ...
- 本地项目上传到Git仓库
1. 进入项目主目录,打开Git Bash,执行以下命令,将项目变为一个git管理的项目: $ git init 执行成功后,会在项目根目录生成一个.git的文件夹. 可以执行以下命令查看项目状态: ...
- Python从0到1丨详解图像锐化的Sobel、Laplacian算子
本文分享自华为云社区<[Python从零到壹] 五十八.图像增强及运算篇之图像锐化Sobel.Laplacian算子实现边缘检测>,作者: eastmount . 一.Sobel算子 So ...