【JUC源码解析】DelayQueue
简介
基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首。只有过期的元素才能出队,在此之前,线程等待。
源码解析
属性
private final transient ReentrantLock lock = new ReentrantLock(); // 可重入锁
private final PriorityQueue<E> q = new PriorityQueue<E>(); // 优先级队列
private Thread leader = null; // 领导者线程,成为领导者的线程,只会等待队首元素的delay时间,其他线程会一直等待,直到有线程唤醒它,一直等待的这些线程会伴随着一个个元素的出队相继成为leader,同一时刻,只有一个线程作为领导者等待一个delay时间
private final Condition available = lock.newCondition(); // 条件队列,阻塞的线程会被压入条件队列,等待被唤醒
构造方法
public DelayQueue() {
}
public DelayQueue(Collection<? extends E> c) {
this.addAll(c);
}
关键方法
offer(E e)
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
q.offer(e); // 入队
if (q.peek() == e) { // 队首元素更新为新加入的元素
leader = null; // 上一个领导者线程同其他线程一样被同等对待(等着被唤醒),重新抢占leader,其实不必抢占(因为只有一个线程被唤醒),只不过leader线程等待的delay需要更新(新的队首元素的delay值)
available.signal(); // 只会唤醒Condition队列的队首线程
}
return true;
} finally {
lock.unlock(); // 释放锁
}
}
take()
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 响应中断
try {
for (;;) {
E first = q.peek(); // 取出队首元素
if (first == null) // 若为空
available.await(); // 说明队列为空,线程等待
else {
long delay = first.getDelay(NANOSECONDS); // 否则,获取first的delay值
if (delay <= 0) // 若已到期
return q.poll(); // 弹出此元素
first = null; // 线程等待时,不保持对元素的引用,
if (leader != null) // 领导者线程不为空,则等待
available.await();
else {
Thread thisThread = Thread.currentThread(); // 否则,设置当前线程为领导者线程
leader = thisThread;
try {
available.awaitNanos(delay); // 等待delay时间
} finally {
if (leader == thisThread) // 等待结束后,如果自己是领导者线程,重置leader为null
leader = null;
}
}
}
}
} finally {
if (leader == null && q.peek() != null) // 如果自己是领导线程(上面把leader置为null了),并且有元素,则唤醒其他线程(其中一个,下一届的leader,如此循环下去)
available.signal();
lock.unlock(); // 释放锁
}
}
leader线程,leader-follower模式,当真省去了不必要的出队入队操作(出入的是Condition的队列,出入者是唤醒又马上要等待的线程)
每一届的leader线程对应当前的队首元素,当这届leader线程拿到元素后,会空出leader位置,并唤醒其中等待时间最长的线程成为下一届的leader,如此传递下去。
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_delayqueue.html
【JUC源码解析】DelayQueue的更多相关文章
- 【JUC源码解析】ScheduledThreadPoolExecutor
简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...
- 【JUC源码解析】SynchronousQueue
简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...
- 【JUC源码解析】ForkJoinPool
简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ...
- 【JUC源码解析】CyclicBarrier
简介 CyclicBarrier,一个同步器,允许多个线程相互等待,直到达到一个公共屏障点. 概述 CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后 ...
- 【JUC源码解析】ConcurrentLinkedQueue
简介 ConcurrentLinkedQueue是一个基于链表结点的无界线程安全队列. 概述 队列顺序,为FIFO(first-in-first-out):队首元素,是当前排队时间最长的:队尾元素,当 ...
- 【JUC源码解析】Exchanger
简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ...
- Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
功能简介: ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列.队列中的元素遵循先入先出(FIFO)的规则.新元素插入到队列的尾部,从队列头部取出元素. 和普通队列有所不同,该队列 ...
- Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue
功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ...
- Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer
功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDow ...
随机推荐
- controller断点进入失败:包路径问题
controller 接受前端参数的方法(前端要有传值给controller的方法,后台要有接收值得方法) 1.@RequestParam 接收表单参数 2.@RequestBody 接收json字符 ...
- Windows Server 2008搭建域控制器
前言 1.为什么要建域 工作组的分散管理模式不适合大型的网络环境下工作,域模式就是针对大型的网络管理需求设计的,就是共享用户账号,计算机账号和安全策略的计算机集合.域中集中存储用户账号的计算机就是域控 ...
- 使用concurrent.futures模块并发,实现进程池、线程池
Python标准库为我们提供了threading和multiprocessing模块编写相应的异步多线程/多进程代码 从Python3.2开始,标准库为我们提供了concurrent.futures模 ...
- 数据结构&堆&heap&priority_queue&实现
目录 什么是堆? 大根堆 小根堆 堆的操作 STL queue 什么是堆? 堆是一种数据结构,可以用来实现优先队列 大根堆 大根堆,顾名思义就是根节点最大.我们先用小根堆的建堆过程学习堆的思想. 小根 ...
- Joinpoint继承体系-笔记
Joinpoint继承层次图: 由上图可以知道的所有的接口的实现都在ReflectiveMethodInvocation这个类中.ConstructorInvocation接口只有一个方法,这个方法的 ...
- luogu P2709 小B的询问
嘟嘟嘟 莫队板子. 记住:删除是先删除再移动,添加是先移动在添加! #include<cstdio> #include<iostream> #include<cmath& ...
- Centos7配置samba
Centos7配置samba 1.安装 yum install samba samba-client samba-common -y 2.配置 备份已有配置mv /etc/samba/smb.conf ...
- 包学会之浅入浅出Vue.js:结业篇
在第一篇<包学会之浅入浅出Vue.js:开学篇>和上一篇<包学会之浅入浅出Vue.js:升学篇>的学习中,我们首先了解了Vue环境的搭建以及两个重要思想——路由和组件的学习,通 ...
- better-scroll在vue中的坑
在我们日常的移动端项目开发中,处理滚动列表是再常见不过的需求了,以滴滴为例,可以是这样竖向滚动的列表,如图所示: 也可以是横向滚动的导航栏,如图所示: 可以打开“微信 —> 钱包—>滴滴出 ...
- Node学习笔记之模块实现
一.模块分类 由Node提供的模块,称为核心模块:部分核心模块在Node源代码的编译过程中,编译进了二进制执行文件.在node进程启动时,该部分就直接加载进内存,文件定位和编译执行的步骤可以省略掉,并 ...