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

Timer实现定时调度的原理是什么?

Java中的Timer类是一个定时调度器,用于在指定的时间点执行任务。JDK 中Timer类的定义如下:

public class Timer {/*** The timer task queue.  This data structure is shared with the timer* thread.  The timer produces tasks, via its various schedule calls,* and the timer thread consumes, executing timer tasks as appropriate,* and removing them from the queue when they're obsolete.*/private final TaskQueue queue = new TaskQueue();/*** The timer thread.*/private final TimerThread thread = new TimerThread(queue);
}

以上就是Timer中最重要的两个成员变量:

1. TaskQueue:一个任务队列,用于存储已计划的定时任务。任务队列按照任务的执行时间进行排序,确保最早执行的任务排在队列前面。在队列中的任务可能是一次性的,也可能是周期性的。2. TimerThread:Timer 内部的后台线程,它负责扫描 TaskQueue 中的任务,检查任务的执行时间,然后在执行时间到达时执行任务的 run() 方法。

任务的定时调度的核心代码就在TimerThread中:

class TimerThread extends Thread {boolean newTasksMayBeScheduled = true;/*** 存储 TimerTask 的队列*/private TaskQueue queue;TimerThread(TaskQueue queue) {this.queue = queue;}public void run() {try {mainLoop();} finally {synchronized (queue) {newTasksMayBeScheduled = false;queue.clear(); }}}/*** 主要的计时器循环。 */private void mainLoop() {while (true) {try {TimerTask task;boolean taskFired;synchronized (queue) {// 等待队列变为非空while (queue.isEmpty() && newTasksMayBeScheduled)queue.wait();if (queue.isEmpty())break; // 队列为空,将永远保持为空;线程终止// 队列非空;查看第一个事件并执行相应操作long currentTime, executionTime;task = queue.getMin();synchronized (task.lock) {if (task.state == TimerTask.CANCELLED) {queue.removeMin();continue;  // 无需执行任何操作,再次轮询队列}currentTime = System.currentTimeMillis();executionTime = task.nextExecutionTime;if (taskFired = (executionTime <= currentTime)) {if (task.period == 0) { // 非重复,移除queue.removeMin();task.state = TimerTask.EXECUTED;} else { // 重复任务,重新安排queue.rescheduleMin(task.period < 0 ? currentTime   - task.period: executionTime + task.period);}}}if (!taskFired) // 任务尚未触发;等待queue.wait(executionTime - currentTime);}if (taskFired)  // 任务触发;运行它,不持有锁task.run();} catch (InterruptedException e) {}}}
}

可以看到,TimerThread的实际是在运行mainLoop方法,这个方法一进来就是一个while(true)的循环,他在循环中不断地从TaskQueue中取出第一个任务,然后判断他是否到达执行时间了,如果到了,就触发任务执行。否则就继续等一会再次执行。不断地重复这个动作,从队列中取出第一个任务进行判断,执行。。。

这样只要有新的任务加入队列,就在队列中按照时间排序,然后唤醒timerThread重新检查队列进行执行就可以了。代码如下:

private void sched(TimerTask task, long time, long period) {if (time < 0)throw new IllegalArgumentException("Illegal execution time.");// Constrain value of period sufficiently to prevent numeric// overflow while still being effectively infinitely large.if (Math.abs(period) > (Long.MAX_VALUE >> 1))period >>= 1;synchronized(queue) {if (!thread.newTasksMayBeScheduled)throw new IllegalStateException("Timer already cancelled.");synchronized(task.lock) {if (task.state != TimerTask.VIRGIN)throw new IllegalStateException("Task already scheduled or cancelled");task.nextExecutionTime = time;task.period = period;task.state = TimerTask.SCHEDULED;}//新任务入队列queue.add(task);//唤醒任务if (queue.getMin() == task)queue.notify();}}

http://www.xdnf.cn/news/1238797.html

相关文章:

  • ORA-12514:TNS: 监听程序当前无法识别连接描述符中请求的服务
  • 【2025/08/03】GitHub 今日热门项目
  • 案例介绍|JSON数据格式的转换|pyecharts模块简介
  • 计算机网络(TCP篇)
  • io_setup系统调用及示例
  • C++编译过程与GDB调试段错误和死锁问题
  • 【前端:Html】--1.2.基础语法
  • 源代码本地安装funasr
  • 【Linux网络编程基础--socket地址API】
  • 01数据结构-时间复杂度和空间复杂度
  • FreeRTOS源码分析三:列表数据结构
  • 线程锁-互斥、自旋、读写、原子操作、线程池
  • 江协科技STM32 14-1 WDG看门狗
  • Python篇---环境变量软件安装
  • 【视频内容创作】PR的关键帧动画
  • C++23 Concepts:用类型约束重构泛型编程的终极方案
  • k8s+isulad 国产化技术栈云原生技术栈搭建2-crictl
  • io_cancel系统调用及示例
  • 数据结构:单向链表的函数创建
  • 二叉树的锯齿形层次遍历
  • 思途JSP学习 0802(项目完整流程)
  • day 44 文件的规范书写与拆分
  • 《 ThreadLocal 工作机制深度解析:高并发场景的利与弊》
  • Spring+K8s+AI实战:3全栈开发指南
  • Redis实战(7)-- 高级特性 Redis Stream数据结构与基础命令
  • HCIE-Datacom题库_07_设备【道题】
  • kafka与其他消息队列(如 RabbitMQ, ActiveMQ)相比,有什么优缺点?
  • Qt-vs加载exe图标
  • 日常--详细介绍qt Designer常用快捷键(详细图文)
  • 其它IO函数