前言
定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”。 达到一个设定的时间之后,就执行某个指定好的代码,比如:
在受上述场景中,当客户端发出去请求之后, 就要等待响应,如果服务器迟迟没有响应,也不清楚,这个请求就没发过去? 响应丢了?服务器出问题了?
对于客户端来说,不能无限的等,需要有一个最大的期限,到达这个最大的期限之后,是重新再发一遍,还是彻底放弃,还是什么其他的方式。
类似于以上场景就需要用到定时器。
一、标准库中的定时器
在标准库中提供了一个 Timer 类,它的核心方法为 schedule 。
schedule方法 包含两个参数:
- 第一个参数指定即将要执行的任务代码;
- 第二个参数指定多长时间之后执行 (单位为毫秒)。
参考代码如下:
Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("hello"); } }, 3000);
二、实现一个定时器
在实现一个定时器(Timer)前,我们需要考虑三个问题
- Timer 中需要有一个线程,扫描任务是否到时间,可以执行了;
- 需要有一个数据结构,把所有的任务都保存起来;
- 还需要创建–人类,通过类的对象来描述一个任务(至少要包含任务内容和时间);
2.1 定时器的构成
1. 一个带优先级的阻塞队列;
为社么要带优先级呢?
因为阻塞队列中的任务都有各自的执行时刻 (delay)。最先执行的任务一定是 delay 最小的。使用带优先级的队列就可以高效的把这个 delay 最小的任务找出来。
2. 队列中的每个元素是一个 Task 对象;
3.Task 中带有一个时间属性, 队首元素就是即将要执行的对象;
4. 同时有一个 worker 线程一直扫描队首元素, 看队首元素是否需要执行。
2.2实现过程
定时器的完整实现代码:
package Timer9; import java.util.PriorityQueue; /** * @author Zhang * @date 2024/5/1016:43 * @Description: */ //通过这个类,描述了一个任务 class MyTimerTak implements Comparable{ //要有一个要执行的任务 private Runnable runnable; //执行任务的时间 private long time; // 此处的delay,就是schedule方法传入的相对时间 public MyTimerTak(Runnable runnable, long delay ) { this.runnable = runnable; this.time = System.currentTimeMillis()+delay; } @Override public int compareTo(MyTimerTak o) { //这样写,就是让队首元素是最小时间的值 return (int)(this.time - o.time); } public long getTime(){ return time; } public Runnable getRunnable(){ return runnable; } } //自己的定时器 class MyTimer{ //使用一个数据结构,保存所有要安排的任务 PriorityQueue queue = new PriorityQueue<>(); //使用这个ui想作为锁对象 private Object locker = new Object(); public void schedule(Runnable runnable,long delay){ synchronized (locker){ queue.offer(new MyTimerTak(runnable, delay)); } } //扫描线程 public MyTimer(){ //创建一个线程 Thread t = new Thread(()->{ while (true){ try{ synchronized (locker){ //不要使用if 作为wait的判定条件,应该使用while //使用 while 的目的是为了在 wait被唤醒的时候,再次确认一下条件 while(queue.isEmpty()){ //使用wait等待 //这里的wait,需要另外的线程唤醒 //添加了新任务,就会被唤醒 locker.wait(); } MyTimerTak tak = queue.peek(); //比较当前的队首是否可以执行元素 long curTime = System.currentTimeMillis(); if (curTime >= tak.getTime()){ //当前时间已经达到了人物事件,就可以执行任务了 tak.getRunnable().run(); //任务执行结束,就可以从队列中删除了 queue.poll(); }else { //当前时间还没达到任务时间,暂时不执行任务 locker.wait(tak.getTime() - curTime); } } } catch(InterruptedException e){ e.printStackTrace(); } } }); t.start(); } }
定时器的调用和演示:
public class Demo2 { public static void main(String[] args) { MyTimer timer = new MyTimer(); timer.schedule(new Runnable() { @Override public void run() { System.out.println("3000"); } },3000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("2000"); } },2000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("1000"); } },1000); } }
总结
以上就是今天要讲的内容,本文仅仅简单介绍定时器的使用场景,标准库中的定时器,定时器的实现代码。
还没有评论,来说两句吧...