延迟队列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. 领扣(LeetCode)N叉树的层序遍历 个人题解

    给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明: 树的深度不会超过 100 ...

  2. 某些机root也不能访问dma-buf

    从4.3后,回顾<从surfaceflinger历史变更谈截屏>,只能通过生产消费者队列向surfaceflinger服务申请显示缓冲,这个缓冲就是dma-buf映射的共享内存. bind ...

  3. 遗忘root密码,应该如何修改?[CentOS7.5]

    https://www.lanzous.com/i71hw6d 下载视频演示 实验环境:VMware Workstation [CentOS7.5]遗忘root用户密码 应该如何修改??? 设置BIO ...

  4. 在SQL Server数据库中执行存储过程很快,在c#中调用很慢的问题

    记录工作中遇到的问题,分享出来: 原博客地址:https://blog.csdn.net/weixin_40782680/article/details/85038281 今天遇到一个比较郁闷的问题, ...

  5. 网络图片的获取以及二级缓存策略(Volley框架+内存LruCache+磁盘DiskLruCache)

    在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...

  6. [Odoo12基础教程]之开发过程中可能出现的问题

    可能出现的问题 更改代码后无变化 当你对代码进行更改之后,发现页面并没有变化,那么请尝试依次以下几种办法: 1.重启项目: 2.升级模块: 3.在开发者模式下刷新本地模块列表: 4.给data列表添加 ...

  7. Python执行系统命令的四种方法

    一.os.system方法 在子终端运行系统命令,可以获取命令执行后的返回信息以及执行返回的状态.执行后返回两行结果,第一行是结果, 第二行是执行状态信息,如果命令成功执行,这条语句返回0,否则返回1 ...

  8. 【Android - 自定义View】之View的位置参数

    View是Android中所有控件的基类,不管是简单的Button和TextView,还是复杂的RelativeLayout和ListView,其基类都是View类:ViewGroup也继承了View ...

  9. 【黑客基础】Windows PowerShell 脚本学习(上)

    视频地址:[黑客基础]Windows PowerShell 脚本学习 2019.12.05 学习笔记 1.$PSVersionTable :查看PowerShell的版本信息. 2.PowerShel ...

  10. Vue项目解析

    各个文件夹 node_modules:用来放环境依赖 public:用来放公共资源,里面的index.html文件,就是初始的挂载点.被app.vue给取代了. src:放各种资源的. assets: ...