DelayQueue 源码
调用 demoimportjava.util.concurrent.DelayQueue;importjava.util.concurrent.Delayed;importjava.util.concurrent.TimeUnit;classTaskimplementsDelayed{privatelongexpire;privateStringname;publicTask(Stringname,longdelay,TimeUnitunit){this.namename;this.expireSystem.currentTimeMillis()unit.toMillis(delay);}OverridepubliclonggetDelay(TimeUnitunit){longremainexpire-System.currentTimeMillis();returnunit.convert(remain,TimeUnit.MILLISECONDS);}OverridepublicintcompareTo(Delayedo){returnLong.compare(this.getDelay(TimeUnit.MILLISECONDS),o.getDelay(TimeUnit.MILLISECONDS));}OverridepublicStringtoString(){returnname;}}publicclassDelayQueueMain{publicstaticvoidmain(String[]args)throwsInterruptedException{DelayQueueTaskqueuenewDelayQueue();queue.put(newTask(1s任务,1,TimeUnit.SECONDS));queue.put(newTask(3s任务,3,TimeUnit.SECONDS));queue.put(newTask(2s任务,2,TimeUnit.SECONDS));for(inti0;i3;i){Tasktqueue.take();// 取出到期1s任务// 取出到期2s任务// 取出到期3s任务System.out.println(取出到期t);}}}成员变量// 底层最小堆存储延迟元素privatefinalPriorityQueueEqnewPriorityQueueE();// 全局独占锁所有读写加锁privatefinalReentrantLocklocknewReentrantLock();// 等待条件无到期元素/队空时阻塞take线程privatefinalConditionavailablelock.newCondition();// Leader-Follower 优化标记privateThreadleadernull;构造方法// 无参构造器 main new 时执行 publicDelayQueue(){}// 带集合构造器main未使用附原版publicDelayQueue(Collection?extendsEc){this.addAll(c);}入队方法putpublicvoidput(Ee){offer(e);}addpublicbooleanadd(Ee){returnoffer(e);}offer超时publicbooleanoffer(Ee,longtimeout,TimeUnitunit){returnoffer(e);}offerpublicbooleanoffer(Ee){finalReentrantLocklockthis.lock;lock.lock();try{q.offer(e);// 放入堆自动上浮排序// 如果新元素是堆顶清空 leader 并唤醒 1 个线程if(q.peek()e){leadernull;available.signal();}returntrue;}finally{lock.unlock();}}出队方法takepublicEtake()throwsInterruptedException{finalReentrantLocklockthis.lock;lock.lockInterruptibly();// 可中断锁响应线程interrupttry{for(;;){// 死循环自旋校验队首Efirstq.peek();// 分支1队列为空无限阻塞等待if(firstnull)available.await();else{longdelayfirst.getDelay(NANOSECONDS);// 分支2队首已到期直接弹出返回if(delay0)returnq.poll();// 未到期释放引用防止内存泄漏firstnull;// 分支3已有 leader 线程当前线程永久阻塞if(leader!null)available.await();else{// 无leader当前线程成为 leader定时等待剩余延迟ThreadthisThreadThread.currentThread();leaderthisThread;try{available.awaitNanos(delay);}finally{// 等待结束清空leader标记if(leaderthisThread)leadernull;}}}}}finally{// 释放锁前如果无 leader 且队列有元素唤醒一个等待线程if(leadernullq.peek()!null)available.signal();lock.unlock();}}pollpublicEpoll(){finalReentrantLocklockthis.lock;lock.lock();try{Efirstq.peek();// 空 或 未到期 返回nullif(firstnull||first.getDelay(NANOSECONDS)0)returnnull;elsereturnq.poll();}finally{lock.unlock();}}总结无界阻塞队列put/offer 永不阻塞无容量限制底层最小堆队首一定是最快到期元素线程安全全局一把 ReentrantLock 所有操作都会上锁leader 等待优化减少多线程定时竞争提升并发性能仅到期可出队take/poll 不会返回未到期元素未到期线程阻塞相关考点first null 为什么可以防止内存泄漏不执行 first null 时的引用关系如下阻塞线程的局部变量 first 引用堆顶延迟任务对象 Delayed TaskDelayQueue 内部 PriorityQueue 也引用同一个 Task当线程执行到 available.await() / awaitNanos() 阻塞时线程挂起、长时间休眠线程栈帧不会销毁局部变量 first 会一直存活双重强引用导致 GC 无法回收队列里本来就有一份引用再加线程局部变量的强引用当这个任务到期被别的线程 poll 取出、从堆里删掉当前阻塞线程的变量 first 依旧死死持有该对象只要线程没被唤醒、栈帧没退出Task 及其关联大内存就无法被 GC长时间大量阻塞线程会造成内存泄漏底层组成存储PriorityQueue 无界最小堆依靠 Delayed 的 compareTo 排序锁全局一把 ReentrantLock 独占锁所有读写串行条件变量Condition available空队列 / 未到期时阻塞 take 线程优化标记Thread leaderLeader-Follower 等待模型元素强制约束存入元素必须实现 Delayed 接口getDelay(TimeUnit)判断是否到期的核心方法返回负数 已过期compareTo堆排序依据必须用剩余延迟时间比较写反会取出顺序错乱队列边界特性无界阻塞队列put/offer/add 永远不会阻塞不存在满队列remainingCapacity 固定返回 Integer.MAX_VALUEoffer 核心逻辑加锁 → 堆入队排序 → 判断新元素是否为堆顶if (q.peek() e)新任务是最快到期元素清空 leader、signal 唤醒等待线程不是堆顶则不唤醒减少无效系统唤醒take 核心阻塞流程整体死循环自旋逻辑获取可中断锁 lock.lockInterruptibly()取堆顶 peek()队列为空available.await() 无限阻塞有元素计算剩余 delaydelay 0直接poll()弹出返回未到期first null 切断引用防泄漏已有 leaderawait() 永久阻塞无 leader当前线程成为 leaderawaitNanos(delay) 限时等待finally 块释放锁前若无 leader 且队列有元素signal 唤醒一个线程take 中 finally 里为什么要执行 signal当前 leader 线程等待结束退出队列仍有未到期任务唤醒其他 follower 线程竞争新 leaderleader 线程的作用作用解决多线程同时 take 大量定时竞争减少系统唤醒、降低 CPU 自旋机制同一时刻仅允许 1 个 leader 线程执行awaitNanos(剩余延迟)其余 follower 线程全部await()无限阻塞。leader 到期唤醒后follower 才会竞争新 leader。如果没有 leader 机制会有什么问题上千线程同时 take全部执行 awaitNanos 定时等待每个任务到期全部线程同时唤醒竞争锁大量上下文切换、CPU 飙升。为什么新元素是堆顶才唤醒线程场景 1新插入元素变成新堆顶q.peek () e原有堆顶延迟更长新来的任务更快到期举例子原来堆顶是 5s 任务leader 线程等待 5s现在 put 一个 1s 任务堆顶变成 1s。此时存在两个问题旧 leader 还在等 5s但实际 1s 就有任务到期线程白白多等 4s无法及时消费旧 leader 记录的等待时长失效需要重置 leader null让下一次循环重新选出新 leader、等待新的 1s。所以必须leader null 清空旧 leader 标记available.signal() 唤醒阻塞线程重新走一次 take() 循环读取最新堆顶、重新计算等待时间。场景 2新插入元素不是堆顶堆顶不变堆顶还是原来那个最快到期的任务剩余延迟时间没有任何变化。leader 线程等待的时长依然准确不需要唤醒任何线程等到原有堆顶时间到自然唤醒即可如果此时无脑 signal()会造成无效唤醒线程被唤醒抢到锁后再次校验堆顶发现任务还没到期又会阻塞回去。频繁上下文切换拉高 CPU毫无收益。为什么只 signal() 而不是 signalAll()只需要唤醒一个线程重新竞争 leader唤醒全部会造成大量线程同时抢锁竞争加剧如果去掉这段判断每次 put 都执行 signal 会有什么后果每次入队都唤醒阻塞线程大量无效唤醒线程频繁阻塞 / 唤醒切换CPU 飙升并发性能严重下降。为什么要同步执行 leader null旧 leader 等待的是过期的长延迟标记作废唤醒后线程会重新竞争成为新 leader等待更短的延迟。

相关新闻

SUID无障碍访问(a11y)指南:如何构建符合WCAG标准的Material Design应用

SUID无障碍访问(a11y)指南:如何构建符合WCAG标准的Material Design应用

SUID无障碍访问(a11y)指南:如何构建符合WCAG标准的Material Design应用 【免费下载链接】suid A port of Material-UI (MUI) built with SolidJS. 项目地址: https://gitcode.com/gh_mirrors/su/suid 构建无障碍的Web应用是现代前端开…

2026/7/12 19:31:59 阅读更多 →
第7篇:六大设计原则在模板方法中的体现

第7篇:六大设计原则在模板方法中的体现

第7篇:六大设计原则在模板方法中的体现 摘要:模板方法模式如何体现单一职责、开闭原则、里氏替换等六大设计原则?本文用一张对照表和逐条解读,帮你建立模式与原则之间的深层联系,不仅会用,还能讲出设计背后…

2026/7/12 19:29:59 阅读更多 →
【Midjourney材质质感终极指南】:20年AI视觉工程师亲授17种金属/织物/玻璃质感提示词配方与参数调优逻辑

【Midjourney材质质感终极指南】:20年AI视觉工程师亲授17种金属/织物/玻璃质感提示词配方与参数调优逻辑

更多请点击: https://kaifayun.com 第一章:材质质感在AI图像生成中的底层逻辑与视觉心理学基础 材质质感并非图像中简单的纹理叠加,而是人类视觉系统对光—物交互的长期经验建模结果。当AI模型生成一张“磨砂玻璃”图像时,其有效…

2026/7/12 19:29:59 阅读更多 →

最新新闻

基于Web3的落盘加密技术:保护用户数据安全的下一代方案

基于Web3的落盘加密技术:保护用户数据安全的下一代方案

从链上到链下,构建全方位的数据安全防护体系 一、引言:Web3时代的“数据信任危机” “Your keys, your coins”是Web3世界的核心信条。然而,当我们把目光从资产转向数据时,情况却变得复杂起来。 传统区块链的透明性是其核心优势,却也是敏感数据的“阿喀琉斯之踵”。公链…

2026/7/12 20:36:15 阅读更多 →
Introspy-iOS:终极iOS应用安全分析工具,揭秘应用运行时行为

Introspy-iOS:终极iOS应用安全分析工具,揭秘应用运行时行为

Introspy-iOS:终极iOS应用安全分析工具,揭秘应用运行时行为 【免费下载链接】Introspy-iOS Security profiling for blackbox iOS 项目地址: https://gitcode.com/gh_mirrors/in/Introspy-iOS Introspy-iOS是一款强大的iOS应用安全分析工具&#…

2026/7/12 20:36:15 阅读更多 →
Nokhwa开发路线图:未来功能与平台扩展展望

Nokhwa开发路线图:未来功能与平台扩展展望

Nokhwa开发路线图:未来功能与平台扩展展望 【免费下载链接】nokhwa Cross Platform Rust Library for Powerful Webcam/Camera Capture 项目地址: https://gitcode.com/gh_mirrors/no/nokhwa Nokhwa(녹화,韩语意为"录制"&am…

2026/7/12 20:34:14 阅读更多 →
开心消消乐关卡设计全攻略:从配置到障碍物系统实现

开心消消乐关卡设计全攻略:从配置到障碍物系统实现

开心消消乐关卡设计全攻略:从配置到障碍物系统实现 【免费下载链接】kaixinxiaoxiaole 使用cocos creator 编写的三消游戏 开心消消乐 项目地址: https://gitcode.com/gh_mirrors/ka/kaixinxiaoxiaole 开心消消乐是一款基于Cocos Creator 3.8.6开发的经典三消…

2026/7/12 20:34:14 阅读更多 →
ChatGPT、Codex、Plus、Pro:AI 工作流编译器正在重构个人与团队的执行方式

ChatGPT、Codex、Plus、Pro:AI 工作流编译器正在重构个人与团队的执行方式

很多人使用 ChatGPT 和 Codex 时,仍然把它们当成两个工具。 ChatGPT 用来问答、写作、分析。 Codex 用来写代码、读项目、修 bug。 Plus 用来满足日常使用。 Pro 用来支持更高频、更复杂的任务。 这种理解没有错,但还停留在应用层。 如果从更深的系统角度…

2026/7/12 20:32:14 阅读更多 →
终极Windows游戏手柄兼容方案:ViGEmBus让你的任何设备变身专业控制器

终极Windows游戏手柄兼容方案:ViGEmBus让你的任何设备变身专业控制器

终极Windows游戏手柄兼容方案:ViGEmBus让你的任何设备变身专业控制器 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 还在为游戏手柄不兼容而烦恼…

2026/7/12 20:30:13 阅读更多 →

日新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/12 0:03:13 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/12 0:03:14 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/12 0:03:14 阅读更多 →

周新闻

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨

互联网大厂 Java 求职面试:燕双非的搞笑回答与技术探讨 在一个阳光明媚的上午,互联网大厂的面试官坐在桌前,准备迎接他的面试候选人——燕双非,一个以搞笑和幽默著称的程序员。第一轮提问 面试官:燕双非,作…

2026/7/12 0:03:13 阅读更多 →
车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估

车载以太网PMA测试设备选型:示波器、VNA、信号源3类仪器关键参数与预算评估在智能驾驶和车联网技术快速发展的今天,车载以太网作为新一代车载网络的核心传输技术,其物理层性能直接决定了数据传输的可靠性和稳定性。1000BASE-T1作为当前主流的…

2026/7/12 0:03:14 阅读更多 →
VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战,5步完成Keil工程转换

VSCode EIDE 插件 2.0:APM32/STM32 项目迁移实战指南嵌入式开发领域正经历一场工具链的静默革命。当传统Keil用户首次打开VSCode的扩展市场搜索EIDE时,往往会惊讶于这个看似简单的插件竟能重构十余年的开发习惯。本文将揭示如何用五个精准步骤&#xff0…

2026/7/12 0:03:14 阅读更多 →

月新闻