延迟队列DelayQueue take() 源码分析
延迟队列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() 源码分析的更多相关文章
- 【RabbitMQ学习记录】- 消息队列存储机制源码分析
本文来自 网易云社区 . RabbitMQ在金融系统,OpenStack内部组件通信和通信领域应用广泛,它部署简单,管理界面内容丰富使用十分方便.笔者最近在研究RabbitMQ部署运维和代码架构,本篇 ...
- java并发包——阻塞队列BlockingQueue及源码分析
一.摘要 BlockingQueue通常用于一个线程在生产对象,而另外一个线程在消费这些对象的场景,例如在线程池中,当运行的线程数目大于核心的线程数目时候,经常就会把新来的线程对象放到Blocking ...
- JAVA并发(7)-并发队列PriorityBlockingQueue的源码分析
本文讲PriorityBlockingQueue(优先阻塞队列) 1. 介绍 一个无界的具有优先级的阻塞队列,使用跟PriorityQueue相同的顺序规则,默认顺序是自然顺序(从小到大).若传入的对 ...
- ucos队列的实现--源码分析
之前说到事件,讲了事件,信号量和互斥信号量,还有一个队列没说,今天说说队列. 队列是用在任务之间传送多个消息的时候,a任务发送消息,b任务发送消息,然后c任务可以依次去提取出b和a传递的消息,不会造成 ...
- 消息队列中间件 RocketMQ 源码分析 —— Message 存储
- 阿里消息队列中间件 RocketMQ 源码分析 —— Message 拉取与消费(上)
- jQuery.queue源码分析
作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 队列是一种特殊的线性表,它的特殊之处在于他只允许在头部进行删除,在尾部进行插入.常用来表示先进先出的操作(FI ...
- Envoy 源码分析--event
目录 Envoy 源码分析--event libevent Timer SignalEvent FileEvent RealTimeSystem 任务队列 延迟析构 dispacth_thread E ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
随机推荐
- 成员函数指针,动态绑定(vc平台)
上一篇介绍了gcc对成员函数指针做了thunk的处理,本篇介绍vc对成员函数指针如何处理,还有动态绑定相关的处理. 同样用回上一篇的例子: struct point {float x,y;}; str ...
- java版单例模式
单例模式可以说是最常用的设计模式之一,其主要作用就是保证一个类只有一个实例,并且提供一个访问它的全局访问点,严格的控制用户的访问方式. 单例模式又分为懒汉模式和饿汉模式,首先说一下饿汉模式: 饿汉模式 ...
- python进程池与线程池
为什么会进行池化? 一切都是为了效率,每次开启进程都会分配一个属于这个进程独立的内存空间,开启进程过多会占用大量内存,系统调度也会很慢,我们不能无限的开启进程. 进程池原来大概如下图 假设有100个任 ...
- 详解 PHP 中的三大经典模式
单例模式 单例模式的含义: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例.它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用. 单例模式 ...
- vue 原生添加滚动加载更多
vue中添加滚动加载更多,因为是单页面所以需要在跳出页面时候销毁滚动,要不会出现错乱.我们在mounted建立滚动,destroyed销毁滚动. mounted () { window.addEven ...
- API更新#图书信息查询ISBN2.0
ISBN图书查询 自2019年5月8日公布isbn查询接口1.0至今,该图书数据查询服务已被调用八万余次,查得图书11653本,感谢一直使用和关心这个接口的朋友们! 目前网站域名将于2019年 ...
- websrom编译器
webstorm less环境配置 备注: 安装node后,在命令行输入npm install -g less 即可安装less,打开webstorm setting-Tools-FileWatche ...
- mac 下面 vim 编辑器 开启语法高亮
cp /usr/share/vim/vimrc ~/.vimrc 拷贝默认的配置文件 vim ~/.vimrc 编辑该文件 在文件的最后加入 syntax on 保存退出即可
- java 静态变量&静态方法
1. 静态变量是static修饰的成员变量(类变量),若无static修饰,则是实例变量.静态变量是一种全局变量,它属于某个类,不属于某个对象实例,是在各对象实例间共存. 访问静态变量直接通过类名 ...
- 如何重置IE浏览器
1.退出所有程序,包括 Internet Explorer.单击“开始”.在“开始搜索”框中键入 inetcpl.cpl 命令,然后按回车键打开“Inetnet 选项”对话框. 2.单击“高级”选项卡 ...