当前位置 : 主页 > 编程语言 > java >

【多线程】 如何自己实现定时器

来源:互联网 收集:自由互联 发布时间:2022-06-30
@TOC 什么是定时器 定时器是多线程编程中的一个重要的组件 好比一个闹钟 定好一个时间让一个线程去执行 定时器在网络编程中特别常见 比如: 在我们打开浏览器,随便打开一个网页

@TOC


什么是定时器

  • 定时器是多线程编程中的一个重要的组件
  • 好比一个闹钟 定好一个时间让一个线程去执行
  • 定时器在网络编程中特别常见

比如:

在我们打开浏览器,随便打开一个网页如果顺利,马上就能进入网站

但是!有时候由于网络不稳定,或者网站的服务器崩了。那么,此时这里就会一直转圈圈加载。但是浏览器不会一直都在这里等待访问的网站反馈信息。它里面其实有一个等待 的“超时时间”,过了这个时间,它就不会再等待,直接跟你说“访问失败 / 网站不见了”


此时我们很快就能想到 join,有一个用法,在括号里添加指定的 “超时时间”。sleep也可以达到这个效果,sleep(指定休眠时间) 。join 和 sleep 都是基于系统内部的定时器,来实现的

那么,我们就可以使用 代码中的定时器,来实现类似的功能。

先介绍标准库的定时器用法,然后再看看如何自己实现一个定时器


标准库的定时器用法

Timer <-----> java.util.Timer

核心方法 :schedule

schedule,它的功能就跟 它 中文意思一样。每调用一次 schedule‘,就会给定时器 安排一个任务。通过这个方法,就可以把 任务 注册到 定时器内部。而计数器内部是支持 注册 多个任务的。

schedule方法,有两个参数:

  • 任务
  • 多长时间之后执行
  • image-20220509170539546


    如何自己实现一个定时器

    一个问题:Timer 类 的内部需要什么东西?

    从Timer 的 工作内容入手

  • 管理很多的任务
  • 执行时间到了的任务
  • 管理任务又可以细分为 2个:

    1、描述任务(创建一个专门的类来表示一个定时器中的任务【Timer Task】)2、组织任务(使用一定的数据及结构进行组织数据,把一些任务放到一起。) 具体任务顺序为1、描述任务(创建一个专门的类来表示一个定时器中的任务【Timer Task】)2、组织任务(使用一定的数据及结构进行组织数据,把一些任务放到一起。)3、执行时间到了的任务


    1. 描述任务

    // 创建一个类,来描述一个具体的任务 class MyTask{ // 任务具体要做什么 private Runnable runnable; // 任务具体的执行时间:保存任务要执行的毫秒级时间戳 private long time; // after 是一个时间间隙,不是绝对的时间戳的值 public MyTask(Runnable runnable,long after){ this.runnable = runnable; // 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。 this.time = System.currentTimeMillis()+after; } // 通过调用这里 run方法,来执行我们任务具体要做什么 public void run(){ runnable.run(); } }

    2. 组织任务

    image-20220509170750080


    3. 执行时间到了的任务

    需要先执行时间最靠前的任务

    比如:十分钟后,大家去休息一下。但是,当前的我们无法判断这个时间,所以我们需要用一个线程去不断的去检查当前优先队列的首元素,看看当前最靠前的这个任务是不是时间到了

    通过 自己构造的 Mytimer 计时器类 的 构造方法。创建一个线程,帮助我们来进行一个检查

    image-20220509170905709


    上述代码中存在两个非常严重的问题!!!

    image-20220509171011331


    代码

    import java.util.concurrent.PriorityBlockingQueue; // 创建一个类,来描述一个具体的任务 class MyTask implements Comparable<MyTask>{ // 任务具体要做什么 private Runnable runnable; // 任务具体的执行时间:保存任务要执行的毫秒级时间戳 private long time; // after 是一个时间间隙,不是绝对的时间戳的值 public MyTask(Runnable runnable,long after){ this.runnable = runnable; // 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。 this.time = System.currentTimeMillis()+after; } // 通过调用这里 run方法,来执行我们任务具体要做什么 public void run(){ runnable.run(); } public long getTime() { return time; } @Override public int compareTo(MyTask o) { return (int) (this.time - o.time); } } class MyTimer{ // 定时器内部要能够存放多个任务 private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>(); public void schedule(Runnable runnable,long after){ MyTask task = new MyTask(runnable,after); queue.put(task); synchronized(locker){ locker.notify(); } } private Object locker = new Object(); public MyTimer(){ Thread t = new Thread(()->{ while(true){ try { // 取出队首元素 MyTask task =queue.take(); //再比较一下看看当前这个任务时间到了没 long curTime = System.currentTimeMillis(); // 拿当前时间 和 任务执行时间进行比较 if(curTime < task.getTime()){ //时间还没到,把任务再塞回到队列中 queue.put(task); // 指定一个等待时间 synchronized(locker){ locker.wait(task.getTime() - curTime); } }else{ // 时间到了,执行这个任务 task.run(); } } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); } } public class Test25 { public static void main(String[] args) { MyTimer myTimer = new MyTimer(); myTimer.schedule(new Runnable() { @Override public void run() { System.out.println("hello timer"); } },3000); System.out.println("main"); } }
    上一篇:【大家的项目】Rust Base62 库学习和分析
    下一篇:没有了
    网友评论