模拟实现定时器

前言

定时器的功能,就是一个类似于闹钟的到点运行的功能。

 

目录

前言

一、Timer 类

二、分析 Timer 类

三、完整代码实现

结语


一、Timer 类

Java库提供 Timer 类,实现 schedule 方法,给方法提供任务和时间,到时间就运行任务,如:

import java.util.Timer;
import java.util.TimerTask;public class Main {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("111");}},1000);}
}

运行截图:

当当前任务执行完毕之后,线程 timer 是不会结束的, 会一直阻塞等待,直到下一个任务的录入。

二、分析 Timer 类

1)定时器是将多个任务按照时间先后执行,由此一个任务具有任务的具体内容,和执行时间:

class TimerTake{private long time;private Runnable runnable;public TimerTake(long time, Runnable runnable) {this.time = time+System.currentTimeMillis();//当前时间+等待时间this.runnable = runnable;}public long getTime() {return time;}public Runnable getRunnable() {return runnable;}
}

2)执行顺序是按照时间先后,故该TimerTake 类应该带有比较器:

class TimerTake implements Comparable<TimerTake>{private long time;private Runnable runnable;public TimerTake(long time, Runnable runnable) {this.time = time;this.runnable = runnable;}public long getTime() {return time;}public Runnable getRunnable() {return runnable;}@Overridepublic int compareTo(TimerTake o) {return (int)(this.time-o.time);}
}

3)为了更好的实现有一个任务实现一个任务,没有任务等待下一个任务的添加,这里组织任务的数据结构使用阻塞队列(阻塞队列_线程安全版本_生产消费者模型_Y君的进化史的博客-CSDN博客),不过考虑到时间先后顺序,采用阻塞优先级队列更加合理再写一个类MyTimer组织TimerTake类任务的添加在schedule方法中实现

class MyTimer{private PriorityBlockingQueue<TimerTake> queue = new PriorityBlockingQueue<TimerTake>();public void schedule(Runnable runnable,long time){TimerTake timerTake = new TimerTake(runnable,time);queue.put(timerTake);}
}

4)需要在一调用schedule时,按照时间执行任务,说明在MyTimer构造方法中应该存在线程的调用,使其一直运行:

    class Timer extends Thread {@Overridepublic void run() {while(true){if(queue.isEmpty()){//空队列,没有任务}try {TimerTake timerTake = queue.take();long time = System.currentTimeMillis();//当前时间if(time >= timerTake.getTime()){//执行任务timerTake.getRunnable().run();}else{//将任务添加回去queue.put(timerTake);}} catch (InterruptedException e) {e.printStackTrace();}}}}MyTimer(){Timer timer = new Timer();timer.start();}

5)上述代码确实可以处理任务的执行问题,但是一直使用while和if判断会消耗大量的CPU资源,所以选择使用休眠等待时间,有两个选择sleep 和 wait-notify。使用sleep会影响任务的录入,故选择wait-notify:

6)那什么时候使用notify唤醒呢?应该在任务加入的时候使用:

    public void schedule(Runnable runnable,long time){TimerTake timerTake = new TimerTake(runnable,time);queue.put(timerTake);synchronized (object){object.notify();}}

7)队列为空时,采取wait-notify等待-唤醒机制,等任务添加时唤醒:

8)考虑到线程安全问题,整个代码再加上synchronized 和 volatile:



三、完整代码实现

下面代码是Timer的模拟实现:


import java.util.concurrent.PriorityBlockingQueue;class TimerTake implements Comparable<TimerTake>{private long time;private Runnable runnable;public TimerTake( Runnable runnable,long time) {this.time = time+System.currentTimeMillis();//当前时间+等待时间this.runnable = runnable;}public long getTime() {return time;}public Runnable getRunnable() {return runnable;}@Overridepublic int compareTo(TimerTake o) {return (int)(this.time-o.time);}
}class MyTimer {volatile private PriorityBlockingQueue<TimerTake> queue = new PriorityBlockingQueue<TimerTake>();public void schedule(Runnable runnable, long time) {synchronized (object) {TimerTake timerTake = new TimerTake(runnable, time);queue.put(timerTake);object.notify();}}private static Object object = new Object();class Timer extends Thread {@Overridepublic void run() {while (true) {try {synchronized (object) {while (queue.isEmpty()) {//空队列,没有任务object.wait();}TimerTake timerTake = queue.take();long time = System.currentTimeMillis();//当前时间if (time >= timerTake.getTime()) {//执行任务timerTake.getRunnable().run();} else {//将任务添加回去queue.put(timerTake);object.wait(timerTake.getTime() - time);}}} catch (InterruptedException e) {e.printStackTrace();}}}}MyTimer(){Timer timer = new Timer();timer.start();}
}

下面代码是博主通过main方法调用这个模拟的MyTimer实现几个小功能:

public class Main {public static void main(String[] args) {MyTimer myTimer = new MyTimer();myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("111");}},1000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("333");}},3000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("222");}},2000);}
}

运行截图是:


结语

这篇博客如果对你有帮助,给博主一个免费的点赞以示鼓励,欢迎各位🔎点赞👍评论收藏⭐,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/69867.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java:PO、VO、BO、DO、DAO、DTO、POJO

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Java&#xff1a;PO、VO、BO、DO、DAO、DTO、POJO PO持久化对象&#xff08;Persistent Object&#xff09; PO是持久化对象&#xff0c;用于表示数据库中的实体或表…

第六阶|见道明心的笔墨(上)从书法之美到生活之美——林曦老师的线上直播书法课

如果你有需要&#xff0c;可以找我的&#xff0c;我这边有老师的所有课程 如果你有需要&#xff0c;可以找我的&#xff0c;我这边有老师的所有课程

Linux学习之初识Linux

目录 一.Linux的发展历史及概念 1.什么是Linux UNIX发展的历史&#xff1a; Linux发展历史&#xff1a; 2. 开源 商业化发行版本 二. 如何搭建Linux环境 Linux 环境的搭建方式主要有三种&#xff1a; 1. 直接安装在物理机上 2. 使用虚拟机软件 3. 使用云服务器 三. …

设计模式十七:迭代器模式(Iterator Pattern)

迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供了一种访问聚合对象&#xff08;例如列表、集合、数组等&#xff09;中各个元素的方法&#xff0c;而无需暴露其内部表示。迭代器模式将遍历元素和访问元素的责任分离开来&#xff0…

无涯教程-Perl - setservent函数

描述 在第一次调用getservent之前,应先调用此函数。 STAYOPEN参数是可选的,在大多数系统上未使用。当getservent()检索服务数据库中下一行的信息时,然后setervent设置(或重置)枚举到主机条目集的开头。 语法 以下是此函数的简单语法- setservent STAYOPEN返回值 此函数不返…

W5500-EVB-PICO做UDP Client进行数据回环测试(八)

前言 上一章我们用开发板作为UDP Server进行数据回环测试&#xff0c;本章我们让我们的开发板作为UDP Client进行数据回环测试。 连接方式 使开发板和我们的电脑处于同一网段&#xff1a; 开发板通过交叉线直连主机开发板和主机都接在路由器LAN口 测试工具 网路调试工具&a…

C语言 棱形图案

目录 一、问题分析 上部分&#xff1a; 下部分&#xff1a; 二、代码演示 一、问题分析 如上图所示&#xff0c;我们可以将棱形进行拆解&#xff0c;分为上下两个部分。 上部分&#xff1a; 通过观察&#xff0c;我们得到 单边空格数 上半部分总行数 - 行数 - 1 …

【Unity每日一记】方位辨别—向量的叉乘点乘结合

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

uni-app引入sortable列表拖拽,兼容App和H5,拖拽排序。

效果: 拖拽排序 背景&#xff1a; 作为一名前端开发人员&#xff0c;在工作中难免会遇到拖拽功能&#xff0c;分享一个github上一个不错的拖拽js库&#xff0c;能满足我们在项目开发中的需要&#xff0c;下面是我在uniapp中使用SortableJS的使用详细流程&#xff1b; vue开发…

【深度学习--RNN 循环神经网络--附LSTM情感文本分类】

deep learning 系列 --RNN 循环神经网络 什么是序列模型 包括了RNN LSTM GRU等网络模型&#xff0c;主要用途是自然语言处理、语音识别等方面&#xff0c;比如生成乐曲&#xff0c;音频转换为文字&#xff0c;文本情感分类&#xff0c;机器翻译等等 标准模型的缺陷 以往的标…

jenkins pipeline方式一键部署github项目

上篇&#xff1a;jenkins一键部署github项目 该篇使用jenkins pipeline-script一键部署&#xff0c;且介绍pipeline-scm jenkins环境配置 前言&#xff1a;按照上篇创建pipeline任务&#xff0c;结果报mvn&#xff0c;jdk环境不存在&#xff0c;就很疑惑&#xff0c;然后配置全…

bigemap如何添加mapbox地图?

第一步 打开浏览器&#xff0c;找到你要访问的地图的URL地址&#xff0c;并且确认可以正常在浏览器中访问&#xff1b;浏览器中不能访问&#xff0c;同样也不能在软件中访问。 以下为常用地图源地址&#xff1a; 天地图&#xff1a; http://map.tianditu.gov.cn 包含&…