当前位置: 首页 > news >正文

【015】Dubbo3从0到1系列之定时任务

文章目录

  • JDK定时任务管理
  • 七、定时任务管理
    • 7.1 JDK定时任务管理
      • 7.1.1 java.util.TimerTask、java.util.Timer
      • 7.1.2 java.util.concurrent.ScheduledExecutorService
        • 特点:
      • 7.1.3 Java21虚拟线程
      • 7.1.4 JDK实现定时任务管理优缺点总结

JDK定时任务管理

相当于复习一下JDK提供的定时任务管理,若已经非常熟悉,则跳过此部分也可以.

七、定时任务管理

7.1 JDK定时任务管理

7.1.1 java.util.TimerTask、java.util.Timer

这是 JDK 最早提供的定时任务支持,适用于简单的定时调度场景。

  • Timer:调度器,用于安排任务。
  • TimerTask:抽象类,表示一个可被调度的任务(需实现 run() 方法)

✅ 示例代码

/*** @author: laoren* @date: 2025/10/14 16:40* @description: java.utils.timer* @version: 1.0.0*/
public class T2 {public static void main(String[] args) {Timer timer = new Timer();TimerTask task = new TimerTask() {@Overridepublic void run() {System.out.println("hello world");}};// 延迟 1000ms 后开始,每隔 2000ms 执行一次timer.schedule(task, 1000, 2000);}
}

❌ 缺点:

  • 单线程执行:所有任务共享一个线程,如果某个任务执行时间过长或抛出异常,会影响其他任务。
  • 不支持复杂的调度(如 cron 表达式)。
  • 从 Java 5 开始,推荐使用 ScheduledExecutorService 替代。

7.1.2 java.util.concurrent.ScheduledExecutorService

✅ 具体使用方式

import java.util.concurrent.*;public class SchedulerExample {public static void main(String[] args) {// 创建单线程调度器ScheduledExecutorService singleThreadScheduler = Executors.newSingleThreadScheduledExecutor();// 创建多线程调度器ScheduledExecutorService multiThreadScheduler = Executors.newScheduledThreadPool(4);// 使用虚拟线程(JDK 21 新特性)ScheduledExecutorService virtualThreadScheduler =Executors.newScheduledThreadPool(0, Thread.ofVirtual().factory());}
}

创建线程池,指定线程工厂,此时可以传入虚拟线程

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, // 线程核心数ThreadFactory threadFactory // 创建线程的工厂
) {return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

这是 Java 5 引入的更强大、更灵活的定时任务调度接口,属于 java.util.concurrent 包。

特点:
  • 支持多线程(可配置线程池大小)。
  • 提供更丰富的调度方法(固定延迟、固定频率等)。
  • 异常不会影响其他任务(每个任务独立运行)。
  • 更适合生产环境。

✅ 示例代码

package cn.tcmeta.interfaces.test;import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;/*** @author: laoren* @description: TODO* @version: 1.0.0*/
public class T3 {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService= Executors.newScheduledThreadPool(2);scheduledExecutorService.scheduleAtFixedRate(() -> {System.out.println("hello world");// 延迟 1 秒后,每隔 2 秒执行一次}, 1, 2, TimeUnit.SECONDS);}
}

在这里插入图片描述

✅ 常用方法

// 1. 
schedule(Runnable command, long delay, TimeUnit unit):延迟执行一次。
// 2. 
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):固定频率执行。
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):固定延迟执行(上次执行结束后再延迟)。

✅ 对比总结

特性TimerScheduledExecutorService
线程模型单线程多线程(可配置)
异常处理一个任务异常会导致整个 Timer 停止任务独立,互不影响
调度灵活性
推荐使用❌(已过时)✅(推荐)

✅ 补充说明

如果需要更复杂的调度(如 cron 表达式、持久化、分布式调度等),JDK 自带的工具就不够用了,通常会使用第三方框架,例如:

  • Quartz:功能强大的开源调度框架。
  • Spring Task(基于 @Scheduled):Spring 提供的简化调度。
  • XXL-JOB / Elastic-Job:适用于分布式场景。

7.1.3 Java21虚拟线程

简化高并发编程。虚拟线程由 JVM 管理,轻量级、可扩展性强,特别适合 I/O 密集型任务。

虽然虚拟线程本身 不是调度器,但可以结合 ScheduledExecutorService 或其他机制,用虚拟线程来执行定时任务,从而在高并发定时任务场景下获得更好的资源利用率和吞吐量。

✅ 方式一: 使用 Executors.newVirtualThreadPerTaskExecutor() + ScheduledExecutorService(推荐)

⚠️ 注意:ScheduledExecutorService 本身不直接支持虚拟线程,但你可以:

  • 用传统调度器(如 newScheduledThreadPool)来触发任务;
  • 任务提交到虚拟线程执行器中运行。

🆕 创建线程池的时候,可以通过传入线程池创建工作来使用虚拟线程

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, // 线程核心数ThreadFactory threadFactory // 创建线程的工厂
) {return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

✅ 使用示例

定时触发 + 虚拟线程执行

package cn.tcmeta.interfaces.test;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class VirtualThreadScheduledTask {public static void main(String[] args) throws InterruptedException {// 1. 创建一个传统调度器(用于定时触发)ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);// 2. 创建虚拟线程执行器(每个任务一个虚拟线程)ExecutorService virtualExecutor = Executors  .newVirtualThreadPerTaskExecutor();// 定义要处理的任务Runnable task = () -> {System.out.println("任务执行中,线程: " + Thread.currentThread());// 模拟 I/O 或业务处理(虚拟线程在此阻塞不会浪费 OS 线程)try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("任务完成: " + Thread.currentThread());};// 每隔 2 秒调度一次,但实际工作交给虚拟线程scheduler.scheduleAtFixedRate(() -> {virtualExecutor.submit(task);}, 0, 2, TimeUnit.SECONDS);// 主线程等待(生产环境中应优雅关闭)Thread.sleep(10_000);scheduler.shutdown();virtualExecutor.close(); // Java 21+ 支持 AutoCloseable}
}

7.1.4 JDK实现定时任务管理优缺点总结

✅✅✅ 优点

  • 原生无依赖,降低部署成本
  • API简洁直观、学习成本低
  • 线程模型灵活(仅 ScheduledExecutorService)
  • 时间精度更可靠(仅 ScheduledExecutorService)
  • 异常隔离(仅 ScheduledExecutorService)

❌❌❌ 缺点

JDK 自带定时任务的局限性主要体现在功能简陋、缺乏高级能力,无法满足复杂或生产级场景需求:

  • 缺乏复杂调度能力,仅支持基础模式

    • 仅支持三种基础调度逻辑,无法满足 “按日历时间调度”“多周期组合” 等需求:
      • 不支持cron 表达式(如 “每周一凌晨 2 点执行”“每月最后一天 18 点执行”),无法实现灵活的时间规则。
      • 无 “任务优先级”:所有任务同等优先级,无法指定核心任务优先执行(如 “数据备份任务” 优先于 “日志清理任务”)。
      • 无 “动态周期”:任务提交后,无法修改执行周期(如原本每隔 5 分钟执行,需改为每隔 10 分钟,只能取消原任务后重新提交)
  • 任务管理能力弱

    • 仅支持 “提交” 和 “取消”(通过Future.cancel()),无暂停 / 恢复任务依赖(如 “任务 A 执行完后再执行任务 B”)等功能。

    • 无法查询任务状态:没有 API 获取已提交任务的列表、执行状态(如 “等待中”“执行中”“已失败”)、执行次数、耗时等信息,调试和问题排查困难。

  • 无监控与告警机制

    • 无内置监控能力:无法统计任务成功率、平均执行耗时、失败次数等关键指标,需手动埋点(如捕获异常后打印日志、上报监控平台)。
    • 任务失败无默认告警:若任务抛出异常,仅会终止当前任务(ScheduledExecutorService)或所有任务(Timer),无邮件、短信等告警通知,需开发者自行实现。
  • 无持久化与故障恢复

    • 任务仅存于内存:应用重启、崩溃或服务器宕机后,未执行的任务会完全丢失,无法恢复。
    • 不支持分布式部署:无法在多实例集群中协调任务(如避免同一任务在多个实例上重复执行),需额外引入分布式锁、注册中心等组件,复杂度大幅提升。
  • Timer的固定缺陷

    • 虽然 ScheduledExecutorService 已解决 Timer 的问题,但仍有开发者误用 Timer,需明确其缺陷:
      • 单线程串行:所有任务在一个线程中执行,若一个任务执行时间过长(如耗时 10 分钟),后续任务会全部延迟。
      • 异常导致全局崩溃:单个任务抛出未捕获异常,Timer 线程终止,所有后续任务作废。
      • 时间精度受系统时间影响:依赖System.currentTimeMillis(),系统时间回拨可能导致任务重复执行。
  • 固定速率/ 延迟的局限性(ScheduledExecutorService 仍存在)

    • 固定速率(scheduleAtFixedRate):若任务执行时间 > 周期(如周期 3 秒,任务执行 5 秒),线程池会在任务结束后立即执行下一次任务(相当于 “追赶执行”),可能导致任务并发执行(线程池线程足够时),引发线程安全问题;若线程池线程不足,任务会排队,实际周期变长。
    • 固定延迟(scheduleWithFixedDelay):仅保证 “上一个任务结束到下一个任务开始” 的间隔固定(如延迟 2 秒),无法保证 “任务开始时间间隔” 固定(如第一个任务 10:00 开始,执行 5 秒,第二个任务 10:05 开始,间隔 5 秒而非 2 秒),不适合对开始时间精度要求高的场景。
  • 适用场景总结

    • JDK 自带的定时任务(尤其是 ScheduledExecutorService)仅适合单机、轻量级、简单调度需求的场景,例如:

      • 应用内的简单定时任务(如每隔 1 分钟清理本地临时文件、延迟 5 秒发送通知)。
      • 对任务可靠性、监控、分布式无要求的场景(如测试环境、工具类应用)。

      若需满足以下需求,建议使用第三方框架(如 Quartz、XXL-Job、Elastic-Job):

      • 复杂调度(如 cron 表达式、任务优先级)。
      • 分布式部署(避免任务重复执行)。
      • 任务持久化与故障恢复(应用重启后任务不丢失)。
      • 监控、告警与详细的任务管理。

JDK 提供的 java.util.Timer 和 DelayedQueue 等工具类,可以帮助我们实现简单的定时任务管理,其底层实现使用的是这种数据结构,存取操作的复杂度都是 O(nlog(n)),无法支持大量的定时任务。推荐使用【时间轮】

只为引出【时间轮】, 🚀🚀🚀🚀 … enjoy it!!!

http://www.dtcms.com/a/529146.html

相关文章:

  • 网站建设公司的市场营销方案模板织梦网站建设交流群
  • 阿里云认证网站建设题库百度推广的渠道有哪些
  • 微软PM的来历
  • 网站排名优化教程中国企业排行榜前十名
  • 医疗多模态共情推理与学习一体化网络Python实现(2025扩充版)
  • 网络编程:SQLite3数据库
  • Oracle远程连接数据库方式
  • 代码随想录Day61|Floyd 算法精讲、A * 算法精讲
  • 网站开发难吗腾讯网站建设专家
  • 企业网站建设教程视频企业网络营销方案策划书
  • 网站服务器怎么选择做网站可以申请国家补助吗
  • 记一次k8s服务部署之后,访问返回503
  • 【Python】——注释
  • ASP.NET Core Blazor简介和快速入门三(布局和路由)
  • 基于微信小程序的博物馆文创系统
  • Claude Code更换供应商:Base URL和API Key的注意事项
  • 蛋白质组学技术揭秘帕金森病:LiP-MS、BAR、UltraID - LIPA 助力 α- 突触核蛋白研究
  • 网站基本模块管理系统网站模板下载
  • 网站错位免费秒玩小游戏
  • Windows编程+使用C++编写EXE加壳程序
  • 邢台做网站服务商网页平面设计要学什么
  • Vue3和Vue2的生命周期差异
  • 永不倒闭的10大央企seo网页优化平台
  • 做网站的技术支持蒙牛网站是谁做的
  • 河北手机网站制作价格电子商务网站建设 李洪心
  • 基于Double-LCC与NLC补偿网络的三发射-三接收非接触电能传输系统协同控制策略
  • 国外图床 wordpress海外seo网站建设
  • 企业如何利用AI CRM提升市场竞争力—以悟空AI CRM为例
  • Vue3 组件注册
  • 二手旧书网站开发设计报告开发公司以现金方式补贴给客户