延迟队列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这个对象)这个情况。

最新文章

  1. BZOJ 2844 albus就是要第一个出场 ——高斯消元 线性基
  2. Material Design Lite,简洁惊艳的前端工具箱。
  3. AngularJS入门心得4——漫谈指令scope
  4. 【js】将table的每个td的内容自动赋值给其title属性
  5. memcached-repcached
  6. android.view.ViewRootImpl$CalledFromWrongThreadException错误处理
  7. Global.asax中的操作数据库代码无法执行
  8. .net中压缩和解压缩的处理
  9. HTTP meta 设置方法
  10. 学习新手给Android新手的一些学习建议
  11. 编写一条sql命令,sql删除没有中文的表
  12. Golang使用pprof和qcachegrind进行性能监控
  13. JavaWeb(五)之JSTL标签库
  14. H5的语义化标签(PS: 后续继续补充)
  15. Vue与React的异同
  16. introduce of servlet and filter
  17. 缓存数据库-redis数据类型和操作(list)
  18. ubuntun 18.04 安装和配置mysql数据库
  19. Spring ApplicationContext(五)invokeBeanFactoryPostProcessors
  20. 【java】解析java中的数组

热门文章

  1. jQuery简单面试题
  2. [FPGA]Verilog实现JK触发器组成的8421BCD码十进制计数器
  3. 性能测试——记XX银行保全项目性能问题分析优化
  4. UML元素绘制方式
  5. (四十五)golang--反射
  6. windows安装Pytorch报错:from torch._C import * ImportError: DLL load failed: 找不到指定的模块”解决方案
  7. Nginx负载均衡、SSL原理、生成SSL密钥对、Nginx配置SSL
  8. 上传一个项目到GitHub
  9. 比特宇宙-TCP/IP的诞生
  10. Shell入门01-bash Shell特性