JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor
先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码:
/**
* 这个是 {@link DelayQueue} 延时队列 的验证使用类
*/
class MyDelayed implements Delayed {
private long delayTime;//该任务在队列中的延迟时间
private long expire;//这个时间: 表示过时时间+当前时间, 到期时间
private String taskName;//任务名字
@Override
public String toString() {
return "MyDelayed{" +
"delayTime=" + delayTime +
", expire=" + expire +
", taskName='" + taskName + '\'' +
'}';
}
public MyDelayed(long delayTime, String taskName) {
this.delayTime = delayTime;
this.taskName = taskName;
this.expire = System.currentTimeMillis() + delayTime;
}
@Override
public long getDelay(TimeUnit unit) {
// 这个方法是 定义了 剩余到期时间
//unit.convert(), 这个方法是转换, 将数值转换为毫秒, 将延时时间转换为毫秒
return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
// 这里设置比较规则,从小到大
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
// 从大到小
//return (int) ( o.getDelay(TimeUnit.MILLISECONDS) - this.getDelay(TimeUnit.MILLISECONDS));
}
public static void main(String[] args) throws InterruptedException {
boolean flag = true;
/**
* 延迟队列: 这是一个无界队列,添加元素时候不阻塞, 每个任务里面都有一个延迟时间,
* 超过这个时间,才将任务取出来,且这个队列中放的元素,只能是 MyDelayed,(实现了Delayed)
*/
DelayQueue<MyDelayed> delayQueue = new DelayQueue<>();
Random random = new Random();
for (int i = 0; i < 20; i++) {
MyDelayed myDelayed = new MyDelayed(random.nextInt(500), "任务" + i);
delayQueue.put(myDelayed);
}
while (flag) {
// 这里使用 take(). 阻塞获取的方法,当获取不到的时候,会阻塞,直到延时时间到期,获取到为止
//还有一个 获取方法: poll(). 点进源码看到: 延时时间没到,获取结果为null, 当延时时间到了之后,才会获取到结果
MyDelayed take = delayQueue.take();
System.out.println(take);
if (delayQueue.size() == 0) {
flag = false;
}
}
}
}
运行结果: 
PriorityBlockingQueue, 这个队列,是支持优先级排序的 无界队列, 代码演示:
public class PriorityBlockingQueueDemo {
/**
* PriorityBlockingQueue; 无界队列, 添加元素的时候不阻塞
* <p>
* 这个队列是基于优先级的阻塞队列, 且只会阻塞消费者,不会阻塞生成者,所以在使用的时候,不能让生成的速度大于消费的速度,否则时间一长,会造成堆空间溢出({@link OutOfMemoryError})
*/
public static void main(String[] args) throws InterruptedException {
boolean flag = true;
// PriorityBlockingQueue 队列中的元素 如果是基本数据类型,默认排序时从小到大, 如果是对象,可以实现Comparable接口来指定排序规则
//PriorityBlockingQueue<String> priorityBlockingQueue = new PriorityBlockingQueue();
PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue();
Random random = new Random();
for (int i = 0; i < 20; i++) {
//priorityBlockingQueue.put("任务"+i);
priorityBlockingQueue.put(new MyTask("任务" + i, random.nextInt(100)));
}
while (flag) {
//String take = priorityBlockingQueue.take();
MyTask take = priorityBlockingQueue.take();
System.out.println(take);
if (priorityBlockingQueue.size() == 0) {
flag = false;
}
}
}
}
class MyTask implements Comparable<MyTask> {
private String taskName;
private int age;
public MyTask(String taskName, int age) {
this.taskName = taskName;
this.age = age;
}
@Override
public String toString() {
return "MyTask{" +
"taskName='" + taskName + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(MyTask o) {
return o.age - this.age;
}
}
运行结果为: 可以看到是按照顺序来取出来的

SynchronousQueue, 这个队列是 不存储元素的队列,(传球手), 用这个队列来实现一个 生产者,消费者, 生产一个,消费一个, 代码如下:
class SynchronousQueueDemo {
private static volatile boolean flag = true;
private static AtomicInteger atomicInteger = new AtomicInteger();
private BlockingQueue blockingQueue;
public SynchronousQueueDemo(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
System.out.println(blockingQueue.getClass().getName());
}
// 生产者
public void producer() throws InterruptedException {
String data = "";
while(flag){
data = atomicInteger.getAndIncrement()+"";//这是产品
TimeUnit.SECONDS.sleep(1);// 1秒生成一个产品
boolean offer = blockingQueue.offer(data);
if(offer){
System.out.println(Thread.currentThread().getName() + "添加成功, 元素为:" + data+"--队列是否为空:"+blockingQueue.isEmpty());
}else{
System.out.println(Thread.currentThread().getName() + "添加失败");
}
}
}
// 消费者
public void consumer() throws InterruptedException {
while(flag){
try {
System.out.println("消费了一个产品:"+blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
}
}
// 停止方法
public void stop(){
this.flag = false;
}
public static void main(String[] args) throws InterruptedException {
/**
* 相当于一个传球手, 不存储元素的队列, 所以容量都为空
*
* SynchronousQueue 它是一个对于元素来说空了才能存入,存在才能取出的队列,只保留一个元素在queue里。
* 但是用处在哪里?如果替换成其它queue,比如ArrayBlockingQueue,会使得哪些事情做不到?
*
* 首先,它也是blockingqueue的一个实现,内部采用的就是ArrayBlockingQueue的阻塞原语,所以在功能上完全可以用ArrayBlockingQueue替换之,
* 但是SynchronousQueue 是轻量级的,SynchronousQueue 不具有任何内部容量,甚至不具有一的容量,我们可以用来在线程间安全的交换单一元素。
* 所以功能比较单一,优势应该就在于轻量吧~
*/
SynchronousQueueDemo synchronousQueue = new SynchronousQueueDemo(new SynchronousQueue());
SynchronousQueueDemo linkedTransferQueue = new SynchronousQueueDemo(new LinkedTransferQueue<String>());
new Thread(()->{
try {
linkedTransferQueue.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
linkedTransferQueue.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
TimeUnit.SECONDS.sleep(5);
synchronousQueue.stop();
}
}
运行结果:
关于定时任务线程池的分析
public static void main(String[] args) {
/**
* corePoolSize:4
* maximumPoolSize: Integer.MAX_VALUE
* keepAliveTime: 0
* 单位: 微秒
* 阻塞队列: DelayedWorkQueue
* 线程工厂: Executors.defaultThreadFactory()
* 拒绝策略: AbortPolicy,
*
*/
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(4);
/**
* 这里引用别人博客:[https://www.cnblogs.com/txmfz/p/10338334.html]()
* 定时任务线程池, 内部使用的队列是: DelayedWorkQueue, 用来定时从队列中取任务
*
* 这里不是直接使用的 DelayQueue(队列放的元素 只能是 Delayed类) ,是因为点进 DelayedWorkQueue源码可以看到内部维护了一个数组:RunnableScheduledFuture[]
* 而 RunnableScheduledFuture 这个类最终是继承了 Delayed 类,
* 他是DelayQueue的扩展, 是: 优先级队列实现+延迟队列实现 说明 DelayedWorkQueue的功能比 DelayQueue更强大,
*/
}
JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor的更多相关文章
- JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑
直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列 public class JucPCdemo03 { /** * 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个 * ...
- JUC 并发编程--10, 阻塞队列之--LinkedBlockingDeque 工作窃取, 代码演示
直接上代码 class LinkedBlockingDequeDemo { // 循环是否结束的开关 private static volatile boolean flag1 = true; pri ...
- Python并发编程之消息队列补充及如何创建线程池(六)
大家好,并发编程 进入第六篇. 在第四章,讲消息通信时,我们学到了Queue消息队列的一些基本使用.昨天我在准备如何创建线程池这一章节的时候,发现对Queue消息队列的讲解有一些遗漏的知识点,而这些知 ...
- JUC 并发编程--06, 阻塞队列(7种), 阻塞等待 api的 代码验证
这些队列的 api ,就是添加队列,出队列,检测对首元素, 由于 add()--remove(), offer()--poll(),太简单这里不做验证, 只验证后二组api: 阻塞等待( put()- ...
- Java并发编程:阻塞队列(转载)
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- 【转】Java并发编程:阻塞队列
在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList),这些工具都为我们编写多线程程 ...
- 12、Java并发编程:阻塞队列
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- (转)Java并发编程:阻塞队列
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- java并发编程学习: 阻塞队列 使用 及 实现原理
队列(Queue)与栈(Stack)是数据结构中的二种常用结构,队列的特点是先进先出(First In First Out),而Stack是先进后出(First In Last Out),说得通俗点: ...
随机推荐
- Linux中的SSH服务
目录 SSH 使用scp在两台Linux间传数据: 基于SSH做远程访问,可以使用ftp服务的相关指令sftp root@192.168.10.10 Openssh公私钥验证: SSH SSH(Sec ...
- Python脚本破解压缩文件口令(zipfile)
环境:Windows python版本2.7.15 Python中操作zip压缩文件的模块是 zipfile . 相关文章:Python中zipfile压缩文件模块的使用 我们破解压缩文件的口令也是用 ...
- mimikatz的使用
mimikatz mimikatz是法国人Gentil Kiwi编写的一款Windows平台下的神器,它具备很多功能,其中最主要的功能是直接从 lsass.exe 进程里获取处于active状态账号的 ...
- 15.PHP_PHP与Ajax
PHP与Ajax 刚刚下班回来地铁上看的这一章,觉得这东西思路可以.确实解决了WEB的两个大的问题,流量和计算量问题.简单说下我的理解,然后在根据资料整理下学习笔记. 两个问题: 1.展示一个WEB网 ...
- Mybatis 遍历 List<Map<String,Object>>
在上一篇博客中总结了MyBatis Plus 实现多表分页模糊查询(链接在最后).返回类型是编写一个专门的vo类.这次是返回List < Map > 前言 编写一个专门的vo返回类,主 ...
- VBO、VAO和EBO
Vertex Buffer Object 对于经历过fixed pipeline的我来讲,VBO的出现对于渲染性能提升让人记忆深刻.完了,暴露年龄了~ //immediate mode glBegin ...
- valgrind 内存泄漏分析
概述 valgrind 官网 https://www.valgrind.org/ valgrind 是 Linux 业界主流且非常强大的内存泄漏检查工具.在其官网介绍中,内存检查(memcheck)只 ...
- 新代(Syntec)机床的IP设置
一.前言 通过以太网来做机床联网数据采集时,第一步通常是设置机床的IP和找网口 二.机床IP如何设置? 步骤一.找到设置IP的界面 [维护]>[网络设定] 步骤二.设置IP 设定[IP地址取得方 ...
- [web] 虚拟机网络设置
三种模式 桥接(Bridged):主机网卡--虚拟网桥--虚拟机网卡,把主机虚拟为交换机,虚拟机ip需与主机设置在同一网段,网关与DNS与主机网卡一致 地址转换(NAT):主机网卡--虚拟NAT设备- ...
- PECcpu2006中执行单个测试程序的方法
PECcpu2006中执行单个测试程序的方法 2010-12-30 11:44:00 maray 阅读数 10055更多 分类专栏: 科学理论 版权声明:本文为博主原创文章,遵循CC 4.0 BY ...