DelayQueue

DelayQueue 是基于 PriorityQueue 实现的线程安全的无界优先级阻塞队列,
队列的头部元素必须在超时后才能移除,元素必须实现 Delayed 接口。

创建实例

    // 控制访问的互斥锁
private final transient ReentrantLock lock = new ReentrantLock();
// 持有元素的优先级队列
private final PriorityQueue<E> q = new PriorityQueue<>(); /**
* 在延迟队列头部超时阻塞等待的线程,当有 leader 时,其他线程将无限期等待下去。
* leader 线程读取到元素之后,必须唤醒其他等待的线程。
*/
private Thread leader; /**
* 当队列为空或有 leader 在阻塞等待时,当前线程将在该条件上阻塞等待。
*/
private final Condition available = lock.newCondition(); /**
* 创建一个空的延迟队列
*/
public DelayQueue() {}

读取元素

    /**
* 移除并获取延时队列的头部元素,如果没有元素超时,则阻塞等待
*/
@Override
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
// 读取队列头部元素
E first = q.peek();
// 1)如果队列为空
if (first == null) {
// 当前线程在 available 条件上阻塞等待
available.await();
} else {
// 获取元素的超时时间
final long delay = first.getDelay(NANOSECONDS);
// 如果元素已经超时
if (delay <= 0L) {
// 则移除并返回头部元素
return q.poll();
}
first = null; // don't retain ref while waiting
// 1)如果已经有线程在阻塞等待
if (leader != null) {
// 当前线程在 available 条件上阻塞等待
available.await();
} else {
// 2)当前线程是第一个阻塞等待的线程
final Thread thisThread = Thread.currentThread();
// 写入 leader
leader = thisThread;
try {
// 阻塞等待指定的超时时间
available.awaitNanos(delay);
} finally {
// 线程被激活后尝试移除 leader
if (leader == thisThread) {
leader = null;
}
}
}
}
}
} finally {
// 如果没有 leader 并且队列中有元素存在
if (leader == null && q.peek() != null) {
// 唤醒其他阻塞等待的线程来读取元素
available.signal();
}
lock.unlock();
}
}

添加元素

    /**
* 将目标元素 e 插入到延时队列中,由于是无界的,该操作不会被阻塞
*/
@Override
public void put(E e) {
offer(e);
} @Override
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 插入元素
q.offer(e);
// 如果当前元素是优先级最高的元素
if (q.peek() == e) {
// 清除 leader
leader = null;
// 唤醒在可用条件上等待的线程
available.signal();
}
return true;
} finally {
lock.unlock();
}
}

DelayQueue 源码分析的更多相关文章

  1. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  2. 【Java并发编程】19、DelayQueue源码分析

    DelayQueue,带有延迟元素的线程安全队列,当非阻塞从队列中获取元素时,返回最早达到延迟时间的元素,或空(没有元素达到延迟时间).DelayQueue的泛型参数需要实现Delayed接口,Del ...

  3. 阻塞队列---ArrayBlockingQueue,LinkedBlockingQueue,DelayQueue源码分析

    阻塞队列和非阻塞队列阻塞队列和非阻塞队列的区别:阻塞队列可以自己阻塞,非阻塞队列不能自己阻塞,只能使用队列wait(),notify()进行队列消息传送.而阻塞队列当队列里面没有值时,会阻塞直到有值输 ...

  4. DelayQueue源码分析

    DelayQueue<E>继承于AbstractQueue<E>实现BlockingQueue<E> 内部变量包括ReentrantLock 类型的lock以及条件 ...

  5. 并发容器之阻塞队列DelayQueue的使用案例及源码分析

    原文连接:(http://www.studyshare.cn/blog-front//blog/details/1167/0 ) 一.队列及阻塞队列概念 1.队列:是一种特殊线性表,特殊之处在于操作是 ...

  6. JUC源码分析-集合篇(八)DelayQueue

    JUC源码分析-集合篇(八)DelayQueue DelayQueue 是一个支持延时获取元素的无界阻塞队列.队列使用 PriorityQueue 来实现. 队列中的元素必须实现 Delayed 接口 ...

  7. 延迟队列DelayQueue take() 源码分析

    延迟队列DelayQueue take() 源码分析 在工作中使用了延迟队列,对其内部的实现很好奇,于是就研究了一下其运行原理,在这里就介绍一下take()方法的源码 1 take()源码 如下所示 ...

  8. ScheduleThreadPoolExecutor源码分析

    ScheduleThreadPoolExecutor源码分析(一) Java中ScheduleThreadPoolExecutor主要用于执行延迟任务或者按照一定的频率执行任务.其中scheduleA ...

  9. lesson2:java阻塞队列的demo及源码分析

    本文向大家展示了java阻塞队列的使用场景.源码分析及特定场景下的使用方式.java的阻塞队列是jdk1.5之后在并发包中提供的一组队列,主要的使用场景是在需要使用生产者消费者模式时,用户不必再通过多 ...

随机推荐

  1. 7.golang的字符串 string

    golang 字符串为不可变的量 ,字符串定义要使用双引号 package main import "fmt" func main() { var xx string = 'xxx ...

  2. 六、JVM — JDK 监控和故障处理工具

    JDK 监控和故障处理工具总结 JDK 命令行工具 jps:查看所有 Java 进程 jstat: 监视虚拟机各种运行状态信息 jinfo: 实时地查看和调整虚拟机各项参数 jmap:生成堆转储快照 ...

  3. Delphi中各个包中包含的控件

    经常有朋友提这样的问题,“我原来在delphi5或者delphi6中用的很熟的控件到哪里去了?是不是在delphi7中没有了呢?这是不是意味着我以前写的代码全都不能够移植到delphi7中来了呢?是不 ...

  4. I - The Values You Can Make (背包求具体方案)

    题目大意 给你n个数,让你用这n个数在组成k的情况下,找到所有的value,这些value也由这n个数组成,且这些value组合在一起能够组成k 解法 看到题目我的想法就是母函数= =不过wa了,后来 ...

  5. P4290 [HAOI2008]玩具取名

    传送门 $dp$ 设 $f[i][j][k]$ 表示初始为 $k$ 时,能否得到 $[i,j]$ 这一段子串 设 $pd[i][j][k]$ 表示长度为二的字符串 $ij$ 能否由 $k$ 得到 然后 ...

  6. W3C标准下的盒模型与IE盒模型

    标准盒模型如下图所示: IE下盒模型如下图所示:

  7. “程序包com.sun.tools.javac.util不存在” 问题解决

    最近工作中在编译打包项目的时候遇到了如标题所示的问题,报这个错误的类是 com.sun.tools.javac.util.Pair.问题很诡异,在Idea可以导入此类,项目启动运行也很正常,但就是在打 ...

  8. java中构造器(Constructor)

    大部分内容转自:http://tech.it168.com/j/2006-05-18/200605181021879.shtml        构造器是一个创建对象时被自动调用的特殊方法,为的是初始化 ...

  9. 关于代码手写UI,xib和StoryBoard

    代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用.Geek们喜欢用代码构建UI,是因为代码是键盘敲出来的,这样可以做到不开IB,手不离开键盘就完成工作,可以专注于编码环境, ...

  10. java中数组的数组问题

    int[] arr = new int[10]; int[] arr2 = arr; arr[1] = 10; arr2[1] = 20; System.out.println(arr[1]); 上面 ...