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

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

1 take()源码 如下所示

public E take() throws InterruptedException {
// 加锁的一个动作 保证获取数据的安全性
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
//peek 方法是去头部数据即第一个数据
E first = q.peek();
if (first == null)
//说明队列为空 调用condition.await()方法,会使得当前线程释放lock然后加入到等待队列中
available.await();
else {
//如果第一个数据不为空 获取消息体的延迟时间(getDelay() 会在消息体内重写 自定义添加延迟时间)
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
//如果延迟时间 小于等于0 说明已经达到了延迟时间 调用poll方法返回消息体
return q.poll();
//如果延迟时间不为空的话 说明还需要等待一段时间 此时重新循环 所以讲frist置为空
first = null;
if (leader != null)
//这里用到了Leader/Followers模式 有兴趣的话可以去百度一下这个模式
//如果leader 不为空 说明已经有线程在监听 即有线程在优先获取队列的首元素
//释放当前线程获取的锁 加入到等待队列中 即 当前线程变成了Followers
available.await();
else {
//如果没有leader 说明没有线程在监听(没有线程在优先获取队列的首元素)
// 将当前线程置为leader线程
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
//让当前线程最长等待 delay 时间 等待
available.awaitNanos(delay);
} finally {
//释放leader权限
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
// 如果leader 为空 且 队列中有数据 说明没有其他线程在在等待
if (leader == null && q.peek() != null)
//唤醒睡眠的线程
available.signal();
//释放锁
lock.unlock();
}
}

注意事项:

一开始不明白为什么将frist置为NULL,后面在网上找了相关的资料了解到,如果不讲first置为Null会导致内存泄漏的问题,具体原因如下所示:

  • 如果不将first置为Null,线程A到达,队首元素还没到出列时间,设置线程A = leader
  • 线程B来了因为leader不为空 则会阻塞,后续线程一样。
  • 假如线程A阻塞完毕之后获取列首元素成功出列,这个时候列首元素应该被回收,但是它还被线程B C ...所持有一直不会被回收就导致了内存泄漏(gc一直无法回收frist这个对象)这个情况。

延迟队列DelayQueue take() 源码分析的更多相关文章

  1. 【RabbitMQ学习记录】- 消息队列存储机制源码分析

    本文来自 网易云社区 . RabbitMQ在金融系统,OpenStack内部组件通信和通信领域应用广泛,它部署简单,管理界面内容丰富使用十分方便.笔者最近在研究RabbitMQ部署运维和代码架构,本篇 ...

  2. java并发包——阻塞队列BlockingQueue及源码分析

    一.摘要 BlockingQueue通常用于一个线程在生产对象,而另外一个线程在消费这些对象的场景,例如在线程池中,当运行的线程数目大于核心的线程数目时候,经常就会把新来的线程对象放到Blocking ...

  3. JAVA并发(7)-并发队列PriorityBlockingQueue的源码分析

    本文讲PriorityBlockingQueue(优先阻塞队列) 1. 介绍 一个无界的具有优先级的阻塞队列,使用跟PriorityQueue相同的顺序规则,默认顺序是自然顺序(从小到大).若传入的对 ...

  4. ucos队列的实现--源码分析

    之前说到事件,讲了事件,信号量和互斥信号量,还有一个队列没说,今天说说队列. 队列是用在任务之间传送多个消息的时候,a任务发送消息,b任务发送消息,然后c任务可以依次去提取出b和a传递的消息,不会造成 ...

  5. 消息队列中间件 RocketMQ 源码分析 —— Message 存储

  6. 阿里消息队列中间件 RocketMQ 源码分析 —— Message 拉取与消费(上)

  7. jQuery.queue源码分析

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 队列是一种特殊的线性表,它的特殊之处在于他只允许在头部进行删除,在尾部进行插入.常用来表示先进先出的操作(FI ...

  8. Envoy 源码分析--event

    目录 Envoy 源码分析--event libevent Timer SignalEvent FileEvent RealTimeSystem 任务队列 延迟析构 dispacth_thread E ...

  9. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

随机推荐

  1. RHEL7.2 SSH无密码登录非root用户

    1 修改三台虚拟机的/ect/hosts文件 [hadoop@hadoop01 ~]$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain ...

  2. spring boot集成shiro-redis时,分布式根据seesionId获取session报错排查总结

    昨天在集成shiro-redis的时候,使用sessionId在其他微服务获取用户的session时,发生错误:There is no session with id [xxx]. 查遍了所有资料,基 ...

  3. jinjia2

    ansible-playbook --become --become-method=su -K copy.yml - hosts: web remote_user: ansible tasks: - ...

  4. PostGIS 报错为org.postgresql.util.PSQLException:错误: Operation on mixed SRID geometries

    说明: 在用Openlayers与Geoserver进行开发,做在线编辑功能时,出现一个问题:每当我新增了一根要素后,再次用wfs的方式进行点击查询时,会报错mixed SRID. 通过研究发现在数据 ...

  5. 父组件向子组件传值时,值已经传过来却没有触发子组件的watch监听,解决~

    需求: 父组件像封装的子组件传值  (父组件属性传值,子组件props接受)   子组件接受后经过处理回显页面; 预想:子组件接受值 , 经过watch监听,在监听中处理数据,回显数据; 问题:子组件 ...

  6. nginx支持wss配置

    nginx证书 nginx.conf配置

  7. /proc/cpuinfo文件解读(超易理解)

    在linux系统中,提供了/proc目录下文件,显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以查/proc/cpuinfo.但是此文件输出项较多,不易理解.例如我们想获取, ...

  8. Winows下安装RabbitMQ

    RabbitMQ的简介 RabbitMQ是一套开源(MPL)的消息队列服务软件,是由 LShift 提供的一个 Advanced Message Queuing Protocol (AMQP) 的开源 ...

  9. 聚类-K-Means

    1.什么是K-Means? K均值算法聚类 关键词:K个种子,均值聚类的概念:一种无监督的学习,事先不知道类别,自动将相似的对象归到同一个簇中 K-Means算法是一种聚类分析(cluster ana ...

  10. Java学习笔记1(基础)

    计算机语言和Java 计算机语言主要由一些指令(包括数字.符号和语法等)组成,可以分为机器语言.汇编语言.高级语言三大类.Java是一种高级计算机语言,是一种可以编写跨平台应用软件.完全面向对象的程序 ...