延迟队列DelayQueue take() 源码分析
2024-10-20 00:33:11
延迟队列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这个对象)这个情况。
最新文章
- BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基
- Material Design Lite,简洁惊艳的前端工具箱。
- AngularJS入门心得4——漫谈指令scope
- 【js】将table的每个td的内容自动赋值给其title属性
- memcached-repcached
- android.view.ViewRootImpl$CalledFromWrongThreadException错误处理
- Global.asax中的操作数据库代码无法执行
- .net中压缩和解压缩的处理
- HTTP meta 设置方法
- 学习新手给Android新手的一些学习建议
- 编写一条sql命令,sql删除没有中文的表
- Golang使用pprof和qcachegrind进行性能监控
- JavaWeb(五)之JSTL标签库
- H5的语义化标签(PS: 后续继续补充)
- Vue与React的异同
- introduce of servlet and filter
- 缓存数据库-redis数据类型和操作(list)
- ubuntun 18.04 安装和配置mysql数据库
- Spring ApplicationContext(五)invokeBeanFactoryPostProcessors
- 【java】解析java中的数组
热门文章
- jQuery简单面试题
- [FPGA]Verilog实现JK触发器组成的8421BCD码十进制计数器
- 性能测试——记XX银行保全项目性能问题分析优化
- UML元素绘制方式
- (四十五)golang--反射
- windows安装Pytorch报错:from torch._C import * ImportError: DLL load failed: 找不到指定的模块”解决方案
- Nginx负载均衡、SSL原理、生成SSL密钥对、Nginx配置SSL
- 上传一个项目到GitHub
- 比特宇宙-TCP/IP的诞生
- Shell入门01-bash Shell特性