【操作系统】定时器(Timer)的实现

这里写目录标题

定时器

一、定时器是什么

定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定

好的代码.

定时器是⼀种实际开发中⾮常常用的组件.

⽐如⽹络通信中,如果对⽅500ms内没有返回数据,则断开连接尝试重连.

类似于这样的场景就需要用到定时器.

二、标准库中的定时器

  • 标准库中提供了⼀个Timer类.Timer类的核⼼⽅法为 schedule .

  • schedule 包含两个参数.第⼀个参数指定即将要执行的任务代码,第⼆个参数指定多⻓时间之后
    执行(单位为毫秒)
    .

java 复制代码
	Timer timer = new Timer();
	timer.schedule(new TimerTask() {
	
		@Override
		public void run() {
			System.out.println("hello");
		}
	}, 3000);

三、实现定时器

定时器的构成:

  1. ⼀个带优先级队列(不要使用PriorityBlockingQueue,容易死锁!)
  2. 队列中的每个元素是⼀个Task对象.
  3. Task中带有⼀个时间属性,队⾸元素就是即将要执行的任务
  4. 同时有⼀个worker线程⼀直扫描队⾸元素,看队⾸元素是否需要执行

详情代码如下:

  1. Timer类提供的核⼼接⼝为schedule,用于注册⼀个任务,并指定这个任务多⻓时间后执行.
java 复制代码
public class MyTimer {
	public void schedule(Runnable command, long after) {
		// TODO
	}
}
  1. Task类用于描述⼀个任务(作为Timer的内部类).⾥⾯包含⼀个Runnable对象和⼀个time(毫秒时间戳)

    这个对象需要放到优先队列中.因此需要实现 Comparable 接⼝.

java 复制代码
class MyTask implements Comparable<MyTask> {

	public Runnable runnable;
	
	// 为了⽅便后续判定, 使用绝对的时间戳.
	public long time;
	
	public MyTask(Runnable runnable, long delay) {
		this.runnable = runnable;
		// 取当前时刻的时间戳 + delay, 作为该任务实际执行的时间戳
		this.time = System.currentTimeMillis() + delay;
	}
	
	@Override
	public int compareTo(MyTask o) {
		// 这样的写法意味着每次取出的是时间最⼩的元素.
		// 到底是谁减谁?? 俺也记不住!!! 随便写⼀个, 执行下, 看看效果~~
		return (int)(this.time - o.time);
	}
}
  1. Timer实例中,通过PriorityQueue来组织若⼲个Task对象.通过schedule来往队列中插⼊⼀个个Task对象.
java 复制代码
class MyTimer {
	// 核⼼结构
	private PriorityQueue<MyTask> queue = new PriorityQueue<>();
	
	// 创建⼀个锁对象
	private Object locker = new Object();
	
	public void schedule(Runnable command, long after) {
	// 根据参数, 构造 MyTask, 插⼊队列即可.
		synchronized (locker) {
			MyTask myTask = new MyTask(runnable, delay);
			queue.offer(myTask);
			locker.notify();
		}
	}
}
  1. Timer类中存在⼀个worker线程,⼀直不停的扫描队⾸元素,看看是否能执行这个任务.
    所谓"能执行"指的是该任务设定的时间已经到达了.
java 复制代码
// 在这⾥构造线程, 负责执行具体任务了.
public MyTimer() {
	Thread t = new Thread(() -> {
		while (true) {
			try {
				synchronized (locker) {
				// 阻塞队列, 只有阻塞的⼊队列和阻塞的出队列, 没有阻塞的查看队⾸元素.
				while (queue.isEmpty()) {
				locker.wait();
			}
				MyTask myTask = queue.peek();
				long curTime = System.currentTimeMillis();
				if (curTime >= myTask.time) {
					// 时间到了, 可以执行任务了
					queue.poll();
					myTask.runnable.run();
				} else {
					// 时间还没到
					locker.wait(myTask.time - curTime);
				}
				}
			} catch (InterruptedException e) {
			e.printStackTrace();
			}
		}
	});
	t.start();
}
相关推荐
明月看潮生9 分钟前
青少年编程与数学 02-019 Rust 编程基础 15课题、错误处理
开发语言·青少年编程·rust·编程与数学
明月看潮生11 分钟前
青少年编程与数学 02-019 Rust 编程基础 19课题、项目发布
开发语言·青少年编程·rust·编程与数学
yy鹈鹕灌顶1 小时前
LeetCode 字符串类题目解析与 Java 实现指南(深度优化版)
java·开发语言·算法·leetcode
这里是小悦同学呀!2 小时前
python学习day2
java·python·学习
阳光_你好3 小时前
简单介绍C++中线性代数运算库Eigen
开发语言·c++·线性代数
菠萝崽.4 小时前
RabbitMQ高级篇-MQ的可靠性
java·分布式·后端·消息队列·rabbitmq·异步编程
万叶学编程5 小时前
@RequestParam 和 @RequestBody、HttpServletrequest 与HttpServletResponse
java
zfj3215 小时前
H2数据库源码学习+debug, 数据库 sql、数据库引擎、数据库存储从此不再神秘
java·数据库·sql·学习·数据库底层原理
编程、小哥哥6 小时前
Java面试实战:从Spring Boot到分布式缓存的深度探索
java·spring boot·redis·微服务·grpc·缓存技术·面试技巧
在未来等你6 小时前
互联网大厂Java求职面试:Spring AI与大模型交互的高级模式与自定义开发
java·微服务·云原生·大模型·spring ai