模拟实现Java中的计时器
- 开源代码
- 2025-08-22 10:24:02

定时器是什么
定时器也是软件开发中的⼀个重要组件. 类似于⼀个 "闹钟". 达到⼀个设定的时间之后, 就执⾏某个指定好的代码. 前端/后端中都会用到计时器.
定时器是⼀种实际开发中⾮常常⽤的组件. ⽐如⽹络通信中, 如果对⽅ 500ms 内没有返回数据, 则断开连接尝试重连. ⽐如⼀个 Map, 希望⾥⾯的某个 key 在 3s 之后过期(⾃动删除). 类似于这样的场景就需要⽤到定时器.
标准库中的定时器
• 标准库中提供了⼀个 Timer 类. Timer 类的核⼼⽅法为 schedule .
• schedule 包含两个参数. 第⼀个参数指定即将要执⾏的任务代码, 第⼆个参数指定多⻓时间之后 执⾏ (单位为毫秒).
// 定时器的使用 public class Demo21 { public static void main(String[] args) { Timer timer = new Timer(); // main 方法中调用 timer.schedule 方法时, // 它只是将任务注册到 Timer 中,并告诉 Timer // 在 3000 毫秒后执行这个任务。 // 任务的执行是由 Timer 内部的守护线程完成的。 timer.schedule(new TimerTask() { @Override public void run() { System.out.println("hello 3"); } }, 3000); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("hello 2"); } }, 2000); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("hello 1"); } }, 1000); System.out.println("程序开始执行!"); } }模拟实现定时器
那么该怎么解决呢?
class MyTimerTask { // 任务啥时候执行. 毫秒级的时间戳. private long time; // 任务具体是啥. private Runnable runnable; public long getTime() { return time; } public Runnable getRunnable() { return runnable; } public MyTimerTask(Runnable runnable, long delay) { // delay 是一个相对的时间差. 形如 3000 这样的数值. // 构造 time 要根据当前系统时间和 delay 进行构造. time = System.currentTimeMillis() + delay; this.runnable = runnable; } } // 定时器的本体 class MyTimer { // 使用优先级队列 来保存上述的N个任务 private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>(); // 定时器的核心方法 就是把要执行的任务添加到队列中 public void schedule(Runnable runnable, long delay) { MyTimerTask task = new MyTimerTask(runnable, delay); queue.offer(task); } // MyTimer 中还需要构造一个 "扫描线程", 一方面去负责监控队首元素是否到点了, // 是否应该执行; // 一方面当任务到点之后,就要调用这里的 Runnable 的 Run 方法来完成任务 public MyTimer() { // 扫描线程 Thread t1 = new Thread(() -> { // 不停地去扫描当前的队首元素 while (true) { try { if (queue.isEmpty()) { continue; } MyTimerTask task = queue.peek(); long curTime = System.currentTimeMillis(); if (curTime > task.getTime()) { // 假设当前时间是 14:01, 任务时间是 14:00, // 此时就意味着应该要执行这个任务了. // 需要执行任务. queue.poll(); task.getRunnable().run(); }else { // 让当前线程休眠一下, 按照时间差来休眠. Thread.sleep(task.getTime() - curTime); } }catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); } }
上述代码写完了计时器的核心逻辑, 但是这份代码中还有几个关键性的问题.
最后完整的模拟实现代码.
import java.util.PriorityQueue; import java.util.Timer; /** * Created with IntelliJ IDEA. * Description: * User: xiaotutu * Date: 2025-02-20 * Time: 21:41 */ class MyTimerTask implements Comparable<MyTimerTask>{ // 任务啥时候执行. 毫秒级的时间戳. private long time; // 任务具体是啥. private Runnable runnable; public long getTime() { return time; } public Runnable getRunnable() { return runnable; } public MyTimerTask(Runnable runnable, long delay) { // delay 是一个相对的时间差. 形如 3000 这样的数值. // 构造 time 要根据当前系统时间和 delay 进行构造. time = System.currentTimeMillis() + delay; this.runnable = runnable; } @Override public int compareTo(MyTimerTask o) { // 认为时间小的, 优先级高. 最终时间最小的元素, 就会放到队首. // 怎么记忆, 这里是谁减去谁?? 不要记!! 记容易记错~~ // 随便写一个顺序, 然后实验一下就行了. return (int) (this.time - o.time); // return (int) (o.time - this.time); } } // 定时器的本体 class MyTimer { // 使用优先级队列 来保存上述的N个任务 private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>(); // 用来加锁的对象 private Object locker = new Object(); // 定时器的核心方法 就是把要执行的任务添加到队列中 public void schedule(Runnable runnable, long delay) { synchronized (locker) { MyTimerTask task = new MyTimerTask(runnable, delay); queue.offer(task); // 每次来新的任务, 都唤醒一下之前的扫描线程. // 好让扫描线程根据最新的任务情况, 重新规划等待时间. locker.notify(); } } // MyTimer 中还需要构造一个 "扫描线程", 一方面去负责监控队首元素是否到点了, // 是否应该执行; // 一方面当任务到点之后,就要调用这里的 Runnable 的 Run 方法来完成任务 public MyTimer() { // 扫描线程 Thread t1 = new Thread(() -> { // 不停地去扫描当前的队首元素 while (true) { try { synchronized (locker) { while (queue.isEmpty()) { // 注意, 当前如果队列为空, 此时就不应该去取这里的 // 元素. 此处使用 wait 等待更合适. // 如果使用 continue, 就会使这个线程 // while 循环运行的飞快, // 也会陷入一个高频占用 cpu 的状态(忙等). //continue; locker.wait(); } MyTimerTask task = queue.peek(); long curTime = System.currentTimeMillis(); if (curTime > task.getTime()) { // 假设当前时间是 14:01, 任务时间是 14:00, 此时就 // 意味着应该要执行这个任务了. // 需要执行任务. queue.poll(); task.getRunnable().run(); }else { // 让当前线程休眠一下, 按照时间差来休眠. // Thread.sleep(task.getTime() - curTime); locker.wait(task.getTime() - curTime); } } }catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); } } public class Demo22 { public static void main(String[] args) { MyTimer timer = new MyTimer(); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello 3"); } }, 3000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello 2"); } }, 2000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello 1"); } }, 1000); System.out.println("程序开始运行"); } }模拟实现Java中的计时器由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“模拟实现Java中的计时器”