首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
如何在 Java 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程

如何在 Java 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程

热心网友
41
转载
2026-05-01
# 如何在 Ja va 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程
可行但仅适用于学习、嵌入式或教学场景;生产环境应优先选用 HashedWheelTimer、ScheduledThreadPoolExecutor 或 Quartz。

在 Ja va 中,用 while 循环模拟时间轮(timing wheel)调度器是可行的。不过,这里必须划个重点:这种实现方式更适合用来理解原理、用于嵌入式轻量场景或者教学演示。如果是在真实的生产环境中,更稳妥的选择是直接使用 HashedWheelTimer(来自 Netty)、ScheduledThreadPoolExecutor 或是功能更全面的 Quartz。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

如何在 Ja va 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程

理解时间轮的核心结构

时间轮算法的核心,并不是去“实时计算下次执行时间”。它的巧妙之处在于,把时间流切分成一个个固定的刻度(我们称之为 tick),每个刻度都对应着一个任务槽(bucket)。任务会根据其延迟时间,被映射到对应的槽位里。主循环每前进一个 tick,就检查当前槽位,并触发其中所有的任务。

这里有几个关键参数需要把握:

  • tickDuration:每个 tick 代表多少毫秒(例如 100ms)。
  • ticksPerWheel:时间轮一圈总共有多少格(例如 64 格)。那么,这个时间轮能处理的最大延迟时间跨度就是 tickDuration × ticksPerWheel
  • currentTime:当前轮次的基准时间(毫秒级,通常会对齐到 tickDuration 的整数倍)。

用 while 实现单层时间轮主循环

下面是一个简化但可运行的单层时间轮调度器骨架。为了聚焦于核心流程,它暂时没有处理线程安全、任务过期重试等复杂情况。

public class SimpleTimingWheel {
    private final long tickDuration;     // 例如 100ms
    private final int ticksPerWheel;     // 例如 64
    private final List[] wheel;
    private volatile long currentTime;   // 当前 tick 开始时间(毫秒)

    @SuppressWarnings("unchecked")
    public SimpleTimingWheel(long tickDuration, int ticksPerWheel) {
        this.tickDuration = tickDuration;
        this.ticksPerWheel = ticksPerWheel;
        this.wheel = new List[ticksPerWheel];
        for (int i = 0; i < ticksPerWheel; i++) {
            this.wheel[i] = new ArrayList<>();
        }
        // 初始化当前时间,对齐到最近的 tick 边界
        this.currentTime = System.currentTimeMillis() - (System.currentTimeMillis() % tickDuration);
    }

    // 添加延迟任务(此实现仅支持延迟时间小于一圈总时长的任务)
    public void addTask(Runnable task, long delayMs) {
        if (delayMs < 0 || delayMs >= tickDuration * ticksPerWheel) {
            throw new IllegalArgumentException("Delay out of range");
        }
        long expiration = System.currentTimeMillis() + delayMs;
        long tick = (expiration - currentTime) / tickDuration;
        int idx = (int) (tick % ticksPerWheel);
        wheel[idx].add(task);
    }

    // 主循环:持续推进时间,每 tick 执行一次
    public void start() {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                long now = System.currentTimeMillis();
                long expectedTime = currentTime + tickDuration;

                // 等待到下一个 tick 的开始时刻(避免 busy-wait)
                if (now < expectedTime) {
                    try {
                        Thread.sleep(expectedTime - now);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }

                // 更新 currentTime(严格对齐 tick 边界)
                currentTime = expectedTime;

                // 触发当前 tick 对应槽位中的所有任务
                // 注意:这里为了简化没有处理异常,实际应用中需要在 task.run() 外包裹 try-catch
                int idx = (int) ((currentTime / tickDuration) % ticksPerWheel);
                List tasks = wheel[idx];
                for (Runnable task : tasks) {
                    task.run();
                }
                tasks.clear(); // 清空已执行的任务
            }
        });
        t.setDaemon(true);
        t.start();
    }
}

立即学习“Ja va免费学习笔记(深入)”;

使用示例与注意事项

调用方式非常简单:

SimpleTimingWheel wheel = new SimpleTimingWheel(100, 64);
wheel.addTask(() -> System.out.println("Hello at " + System.currentTimeMillis()), 300); // 300ms 后执行
wheel.addTask(() -> System.out.println("World!"), 800); // 800ms 后执行
wheel.start();

// 主线程保持运行(否则 JVM 会退出)
Thread.sleep(2000);

在使用这个简化模型时,有几点需要特别注意:

  • 精度限制:最小的延迟单位就是 tickDuration。比如一个 350ms 的任务,实际上会在第 4 个 tick(400ms)时触发。
  • 单圈限制:上述实现只支持延迟时间小于一圈总时长的任务。如果需要处理更大时间跨度的延迟,就需要升级为多层时间轮(例如小时轮、分钟轮、秒轮组合)。
  • 线程安全addTask() 方法和主循环可能不在同一个线程中调用,实际应用中需要加锁(比如 synchronizedReentrantLock)或者使用线程安全的集合。
  • 异常隔离:某个任务的执行抛出了异常,不应该中断整个 while 循环。务必在 task.run() 外部包裹 try-catch 进行隔离。

为什么不用 while 做生产级调度?

虽然用 while 循环可以实现调度,但它本质上是一种 busy-wait 或者依赖 sleep 的模型,存在几个明显的短板:

  • CPU 占用不可控:尤其是在 sleep 精度较差时,可能导致线程频繁唤醒,浪费 CPU 资源。
  • 无法高效管理海量任务:当任务数量成千上万时,简单的链表遍历和清空操作会成为性能瓶颈。
  • 缺乏企业级功能:比如任务取消、状态查询、失败重试、动态优先级调整等,这些在简单循环里很难优雅实现。
  • 运维支持薄弱:没有 JMX 监控、无法动态调整 tick 参数、缺乏可视化的管理界面。

所以,如果真的要在项目中落地,更建议直接使用成熟的方案,比如 io.netty.util.HashedWheelTimer。它的底层虽然也包含了 while 循环、CAS 和无锁队列的思想,但经过了充分的压力测试和优化,是更可靠的选择。

来源:https://www.php.cn/faq/2399771.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

使用位运算优化多条件状态报告的Java实现方法
编程语言
使用位运算优化多条件状态报告的Java实现方法

基于位运算的容差检测报告优化方案 在工业级数据校验场景中,比如木材尺寸的容差检测,我们常常需要根据多个布尔状态(如厚度、宽度、长度是否合格)来组合生成差异化的提示信息。传统的实现方式,往往是写下一长串的 if-else 分支,来覆盖所有可能的逻辑组合。功能虽然能实现,但问题也很明显:代码重复度高,扩

热心网友
05.01
如何在 Java 中使用 ArrayList.ensureCapacity() 减少由于频繁增删导致的数组重分配
编程语言
如何在 Java 中使用 ArrayList.ensureCapacity() 减少由于频繁增删导致的数组重分配

如何在 Ja va 中使用 ArrayList ensureCapacity() 减少由于频繁增删导致的数组重分配 ensureCapacity() 真的能减少重分配吗? 答案是肯定的,但这里有个关键前提:它只对“新增”操作有效,而且必须在执行大量 add() 之前就调用。至于 remove() 操

热心网友
05.01
如何在 Java 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程
编程语言
如何在 Java 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程

如何在 Ja va 中利用 while 循环实现一个简单的基于时间轮算法的定时任务调度流程 可行但仅适用于学习、嵌入式或教学场景;生产环境应优先选用 HashedWheelTimer、ScheduledThreadPoolExecutor 或 Quartz。 在 Ja va 中,用 while

热心网友
05.01
如何在 Java 中使用 String.matches() 编写带有“零宽断言”的高级正则校验表达式
编程语言
如何在 Java 中使用 String.matches() 编写带有“零宽断言”的高级正则校验表达式

如何在 Ja va 中使用 String matches() 编写带有“零宽断言”的高级正则校验表达式 说起 Ja va 里的 String matches() 方法,很多开发者都踩过同一个坑:它要求正则表达式必须从头到尾、完完整整地匹配整个字符串。这相当于在模式前后自动加上了 ^ 和 $。所以,当

热心网友
05.01
怎么在 Java 中使用 String.format() 实现类似 C 语言的格式化输出
编程语言
怎么在 Java 中使用 String.format() 实现类似 C 语言的格式化输出

怎么在 Ja va 中使用 String format() 实现类似 C 语言的格式化输出 String format() 的基本语法和占位符怎么写 很多从 C 语言转过来的开发者,会下意识地把 printf 那套写法直接搬到 Ja va 里。但这里有个关键区别:Ja va 的 String for

热心网友
05.01

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

《洛克王国:世界》隐藏极品精灵蛋获取攻略
游戏攻略
《洛克王国:世界》隐藏极品精灵蛋获取攻略

洛克王国世界隐藏极品精灵蛋获取方法全解析 各位《洛克王国:世界》的训练家们,你是否已经探索了地图上的每一个角落?游戏中其实散布着一些极易被忽略的隐藏宝藏——属性近乎完美的极品精灵蛋。它们潜藏在特定遗迹中,即便完成了主线剧情,许多玩家也可能与之失之交臂。本文将为你悉数揭秘这些稀有精灵蛋的精准位置与获取

热心网友
05.01
cr8.art : AI辅助艺术创作
AI
cr8.art : AI辅助艺术创作

需求人群 首先,艺术创作领域的工作者。无论是绘画、设计,还是数字媒体艺术家,一个能够持续激发灵感的工具总是备受青睐。 上图所示平台,正是为这一群体量身打造的解决方案。 产品特色 那么,它具体能带来哪些不一样的助力?我们不妨拆开来看。 首当其冲的,自然是利用AI技术生成创作灵感。创意枯竭的瓶颈期,谁没

热心网友
05.01
小K电商图-低成本打造优质电商图片
AI
小K电商图-低成本打造优质电商图片

「小K电商图」是什么 简单来说,这是一款商用级的电商AIGC图片工具。它的核心价值,就在于能用极低的成本,帮电商从业者产出高质量的营销图片。对于预算和效率都有要求的团队,这无疑是个值得关注的解决方案。 功能解析 功能设计直击行业痛点,每一项都很有针对性: 无需模特和摄影师:这是成本控制的关键。理论上

热心网友
05.01
《洛克王国:世界》炫彩翼王和龙息帕尔选择推荐
游戏攻略
《洛克王国:世界》炫彩翼王和龙息帕尔选择推荐

洛克王国世界炫彩翼王和龙息帕尔怎么选?平民玩家棱镜球使用指南 许多《洛克王国:世界》的玩家手中仅有一颗珍贵的棱镜球,面对炫彩翼王和炫彩龙息帕尔这两只人气宠物,常常陷入难以抉择的困境。毕竟,棱镜球作为一种稀有的养成资源,获取途径有限,一旦用错便会感到十分可惜。那么,这两只炫彩宠物究竟哪一只更值得你投入

热心网友
05.01
《明日方舟:终末地》洛茜抽取建议
游戏攻略
《明日方舟:终末地》洛茜抽取建议

明日方舟终末地洛茜值得抽吗 全面分析卡池价值与阵容搭配 《明日方舟:终末地》全新六星干员‌洛茜‌,将于‌3月29日12:00‌正式进驻下半段限定卡池【狼珀】特许寻访。这位备受期待的物理 火焰混伤干员,其抽取价值主要取决于玩家现有阵容的构建需求。本文将为你深入解析洛茜的强度定位与适用场景,助你做出最明

热心网友
05.01