Java 用 ScheduledExecutorService 做定时任务:比 Timer 强在哪、异常吞没与优雅关闭
Java 用 ScheduledExecutorService 做定时任务:比 Timer 强在哪、异常吞没与优雅关闭项目里要跑个定时任务:每 5 秒拉一次配置、每分钟清一次缓存。很多人上手就new Timer().schedule(...),能跑就没再管。直到某天线上定时任务莫名其妙全停了——查了半天才发现是某次任务抛了个异常,把整个 Timer 线程干掉了,后面所有任务再也不执行。这篇讲清楚三件事:为什么该用ScheduledExecutorService取代Timer、任务里的异常是怎么被偷偷吃掉的、以及关闭时怎么不丢任务。先看 Timer 的两个致命伤TimertimernewTimer();timer.scheduleAtFixedRate(newTimerTask(){Overridepublicvoidrun(){if(Math.random()0.5){thrownewRuntimeException(模拟任务异常);}System.out.println(任务执行:LocalTime.now());}},0,1000);跑几秒你就会看到:一旦某次run()抛出未捕获异常,整个 Timer 直接崩溃,控制台再无输出。原因是Timer内部只有一个执行线程,异常会终止这个线程,后续所有任务陪葬。第二个坑:Timer 用的是绝对时间。如果系统时钟被回拨(NTP 校时、运维手动改时间),任务调度会错乱。正确写法:ScheduledExecutorServiceScheduledExecutorService用线程池,基于相对延迟调度,是java.util.concurrent里的标准方案。importjava.util.concurrent.*;ScheduledExecutorServiceschedulerExecutors.newScheduledThreadPool(2);// 固定频率:每 1 秒执行一次(从上次开始时间算起)scheduler.scheduleAtFixedRate(()-{System.out.println(fixedRate 任务:LocalTime.now());},0,1,TimeUnit.SECONDS);// 固定延迟:上次执行结束后再等 1 秒(适合任务耗时不稳定的场景)scheduler.scheduleWithFixedDelay(()-{System.out.println(fixedDelay 任务:LocalTime.now());},0,1,TimeUnit.SECONDS);scheduleAtFixedRate和scheduleWithFixedDelay的区别是新手必踩的点:fixedRate:每隔固定周期触发,不管上次跑多久。如果任务耗时超过周期,下次会紧接着执行(任务会堆积)。fixedDelay:等上一次执行完再计时。任务之间永远有固定间隔,不会堆积。拉配置、发心跳这种必须匀速的用 fixedRate;清理、同步这种别重叠就行的用 fixedDelay。关键坑:异常会被静默吞掉这是ScheduledExecutorService最反直觉的地方。它比 Timer 强——一次任务抛异常不会影响别的任务,但它对同一个周期任务的处理是:抛异常后,这个周期任务就再也不调度了,而且异常被默默吞掉,连日志都没有。scheduler.scheduleAtFixedRate(()-{System.out.println(执行前);thrownewRuntimeException(炸了);// 你在控制台看不到这个异常},0,1,TimeUnit.SECONDS);// 只会打印一次执行前,之后这个任务静默消失,程序还继续跑异常去哪了?被包在返回的ScheduledFuture里了,你不get()就永远看不到。所以周期任务里必须自己 try-catch 兜住所有异常,否则任务会悄无声息地阵亡:scheduler.scheduleAtFixedRate(()-{try{doBusiness();// 真正的业务逻辑}catch(Throwablet){// 兜住一切,包括 Error,保证任务能继续下一轮log.error(定时任务执行失败,本轮跳过,t);}},0,1,TimeUnit.SECONDS);记住这条铁律:放进 scheduleAtFixedRate 的 Runnable,内部必须是不抛异常的。任何漏出来的异常都会让这个周期任务永久停摆。优雅关闭:别用 shutdownNow 一刀切程序退出时直接System.exit或者不管线程池,可能导致正在执行的任务被硬中断。正确的关闭姿势分三步:scheduler.shutdown();// 1. 不再接受新任务,已提交的继续执行try{// 2. 给正在跑的任务一点时间收尾if(!scheduler.awaitTermination(10,TimeUnit.SECONDS)){// 3. 超时还没结束,强制中断scheduler.shutdownNow();}}catch(InterruptedExceptione){scheduler.shutdownNow();Thread.currentThread().interrupt();// 恢复中断状态,别吞掉}shutdown():温柔关闭,等已有任务跑完,但周期任务会停止下一次调度。shutdownNow():发中断信号并清空等待队列,适合超时后的兜底。awaitTermination:阻塞等待,给收尾留窗口。Spring 项目里更简单:把 bean 声明成Bean(destroyMethod shutdown),或用PreDestroy触发上面的关闭逻辑,容器停机时自动回收。一个能直接用的封装publicclassSafeScheduler{privatefinalScheduledExecutorServicescheduler;publicSafeScheduler(intpoolSize){// 用带名字的线程工厂,排查问题时能一眼认出是哪个池的线程this.schedulerExecutors.newScheduledThreadPool(poolSize,r-{ThreadtnewThread(r);t.setName(safe-scheduler-t.getId());t.setDaemon(true);// 守护线程,不阻止 JVM 退出returnt;});}publicvoidscheduleAtFixedRate(Runnabletask,longperiod,TimeUnitunit){scheduler.scheduleAtFixedRate(()-{try{task.run();}catch(Throwablet){System.err.println([scheduler] 任务异常,本轮跳过: t.getMessage());}},0,period,unit);}publicvoidshutdown(){scheduler.shutdown();try{if(!scheduler.awaitTermination(10,TimeUnit.SECONDS)){scheduler.shutdownNow();}}catch(InterruptedExceptione){scheduler.shutdownNow();Thread.currentThread().interrupt();}}}小结别再用Timer:单线程、异常会连坐整个调度器、依赖绝对时间。ScheduledExecutorService全面替代它。scheduleAtFixedRate按周期匀速触发(任务会堆积),scheduleWithFixedDelay按上次结束后计时(不重叠),按业务语义选。周期任务内部必须 try-catch 兜住一切异常——漏出来的异常会让这个任务静默停摆,连日志都不给你留。关闭走shutdown()→awaitTermination→ 超时shutdownNow()三段式,给任务收尾留窗口。一句话记忆:ScheduledExecutorService 不会因为一次异常崩掉整个池,但会因为一次异常悄悄弄死那一个周期任务——所以异常绝不能漏出 Runnable。

相关新闻

暗黑破坏神2存档编辑器:免费可视化工具完全指南

暗黑破坏神2存档编辑器:免费可视化工具完全指南

暗黑破坏神2存档编辑器:免费可视化工具完全指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 暗黑破坏神2存档编辑器(d2s-editor)是一款功能强大的免费开源工具,专为暗黑破坏神2…

2026/8/10 12:15:24 阅读更多 →
React 长列表虚拟滚动实战:手写可视区渲染,10 万条数据不卡顿

React 长列表虚拟滚动实战:手写可视区渲染,10 万条数据不卡顿

React 长列表虚拟滚动实战:手写可视区渲染,10 万条数据不卡顿 后台管理系统里经常遇到这种需求:一次性拉回来几万条日志、几万个 SKU,产品说"不想分页,就要滚动加载全部"。你老老实实 list.map() 渲染出来,浏览器直接卡死——10 万个 DOM 节点,首屏白屏两秒,滚动时掉…

2026/8/10 12:15:24 阅读更多 →
Unity粒子系统实现Logo动态特效:从路径点收敛到性能优化全解析

Unity粒子系统实现Logo动态特效:从路径点收敛到性能优化全解析

1. 项目概述:为什么动态Logo特效是品牌视觉的“点睛之笔”在数字内容创作,尤其是游戏、应用启动界面、品牌展示视频中,一个静态的Logo往往显得过于“安静”。当用户点击启动按钮,或者进入一个关键场景时,一个能够“呼吸…

2026/8/10 12:15:24 阅读更多 →

最新新闻

从“大数据请把我推给小伙伴”看分布式任务调度:推送、排队与调度算法

从“大数据请把我推给小伙伴”看分布式任务调度:推送、排队与调度算法

最近在技术社区里,我注意到一个挺有意思的现象:很多开发者,尤其是刚接触分布式系统或数据处理的朋友,在遇到“任务调度”或“资源分配”问题时,第一反应是去搜索“如何保证我的任务被公平处理”或者“为什么我的请求总…

2026/8/10 13:02:41 阅读更多 →
终极ncmdump解密指南:3步释放网易云音乐NCM文件,重获音频自由

终极ncmdump解密指南:3步释放网易云音乐NCM文件,重获音频自由

终极ncmdump解密指南:3步释放网易云音乐NCM文件,重获音频自由 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾为网易云音乐下载的歌曲只能在特定APP播放而烦恼?ncmdump作为一款开源免费的…

2026/8/10 13:02:41 阅读更多 →
为什么你的音乐文件无法在设备间自由播放?解锁音乐格式限制的终极方案

为什么你的音乐文件无法在设备间自由播放?解锁音乐格式限制的终极方案

为什么你的音乐文件无法在设备间自由播放?解锁音乐格式限制的终极方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web …

2026/8/10 13:02:41 阅读更多 →
品牌放弃自建人工监测,转用GEO监测工具背后的成本账

品牌放弃自建人工监测,转用GEO监测工具背后的成本账

在品牌数字营销领域,用户决策入口正在向AI问答平台转移。为了第一时间掌握品牌在AI回答中的曝光表现,不少企业初期尝试通过人工检索、记录和整理数据来建立监测体系。这种方式看似省去了订阅费用,但随着业务规模扩大和AI算法迭代,…

2026/8/10 13:02:41 阅读更多 →
Spring Boot实战:从零构建基于RBAC的权限管理系统

Spring Boot实战:从零构建基于RBAC的权限管理系统

在实际软件开发项目中,权限控制是保障系统安全的核心防线。很多开发者,尤其是刚接触权限体系的初学者,常常会混淆认证(Authentication)与授权(Authorization)的概念,或者虽然知道这两…

2026/8/10 13:02:41 阅读更多 →
NX-HBMenu深度故障排除:10个技术难题的实践解决方案

NX-HBMenu深度故障排除:10个技术难题的实践解决方案

NX-HBMenu深度故障排除:10个技术难题的实践解决方案 【免费下载链接】nx-hbmenu The Nintendo Switch Homebrew Menu 项目地址: https://gitcode.com/gh_mirrors/nx/nx-hbmenu NX-HBMenu作为Nintendo Switch自制系统的核心启动菜单,为Homebrew应用…

2026/8/10 13:01:41 阅读更多 →

日新闻

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南 【免费下载链接】graphql-css A blazing fast CSS-in-GQL™ library. 项目地址: https://gitcode.com/gh_mirrors/gr/graphql-css GraphQL-CSS是一个基于GraphQL的CSS-in-GQL™库&#xff0…

2026/8/10 0:00:02 阅读更多 →
告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍:KISS Translator 双语翻译插件终极指南 【免费下载链接】kiss-translator A simple, open source bilingual translation extension & Greasemonkey script (一个简约、开源的 双语对照翻译扩展 & 油猴脚本) 项目地址: https://gitcode.com/…

2026/8/10 0:00:02 阅读更多 →
BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器:游戏插件配置的终极可视化解决方案 【免费下载链接】BepInEx.ConfigurationManager Plugin configuration manager for BepInEx 项目地址: https://gitcode.com/gh_mirrors/be/BepInEx.ConfigurationManager 你是否曾经因为游戏插件的复杂…

2026/8/10 0:00:02 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/10 1:05:29 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/10 1:05:29 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/10 1:05:29 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/9 17:05:02 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/10 1:05:29 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/9 17:05:02 阅读更多 →