「JavaEE」多线程案例分析2:实现定时器

🎇个人主页:Ice_Sugar_7
🎇所属专栏:JavaEE
🎇欢迎点赞收藏加关注哦!

实现定时器

  • 🍉简介
  • 🍉模拟实现定时器

🍉简介

定时器类似一个闹钟,时间到了之后就会执行相应的任务
Java 标准库中已经实现了一个定时器的类 Timer

Timer timer = new Timer();

在定义好 timer 之后可以调用 schedule 把一个或多个任务(TimerTask)添加到定时器中

timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("2000 ms");}
},2000);

第一个参数就是任务内容,每个任务后面都会带有一个时间(第二个参数),这个时间是“相对时间”,是以 schedule 时的时间为基准,过了相对时间后才执行
比如 2000ms,它表示调用 schedule 后再过 2000ms 就会执行这个任务

TimerTask 里面有一个 run 方法,而 run 是线程的入口,说明 timer 创建了一个线程来执行任务。这个线程是前台线程,它会阻止主线程结束,需要我们使用 cancel 主动结束,否则 Timer 不知道其他地方是否会继续添加任务

public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("2000 ms");timer.cancel(); //结束线程}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("1000 ms");}},1000);
}

在这里插入图片描述


🍉模拟实现定时器

首先要有一个数据结构负责保存 schedule 的任务(相当于任务清单),因为我们是先执行时间近的任务(比如有两个任务,一个是两点执行,另一个是两点半执行,肯定要先完成前者),换而言之,任务之间是有优先级的,所以要用优先级队列
标准库中提供了 PriorityQueue 和 PriorityBlockingQueue,前者是线程不安全的,后者是线程安全的,在此处的场景中 PriorityBlockingQueue 不太好控制,容易出问题,所以我们用前者

(补充:TreeSet 和 TreeMap 虽然也是有序的,但是获取到最小值的时间复杂度为 O(logN),不及 O(1) 的优先级队列)

然后需要有一个线程不断扫描优先级队列的队首元素,看它时间到了没

public class MyTimer {private Thread t;private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();private Object locker = new Object();public MyTimer(){//定时器构造方法的主体就是启动线程,让它去扫描队首元素t = new Thread(() -> {while (true) {synchronized (locker) {while (queue.isEmpty()) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}MyTimerTask task = queue.peek();long curTime = System.currentTimeMillis();if (curTime >= task.getTime()) { //时间到了,执行任务task.run();queue.poll(); //记得执行后把它出队列} else {try {locker.wait(task.getTime() - curTime); //如果还没到执行时间,那就等待,不要一直循环下去} catch (InterruptedException e) {throw new RuntimeException(e);}}}}});t.start();}public void schedule(Runnable runnable,long delay) { //把任务添加到 queue 里面synchronized (locker) {MyTimerTask task = new MyTimerTask(runnable, delay);queue.offer(task);locker.notify(); //添加元素后,就可以唤醒处于 wait 状态的线程}}
}

队列的元素——任务,它是一个类。它的成员变量应该包括时间、能让它跑起来的 Runnable 接口

public class MyTimerTask{private long time; //执行任务的时间(注意这个是“绝对时间”)private Runnable runnable; //持有 Runnable 接口可以调用它的 run 方法,也可以不持有 Runnable,而是实现 Runnable 接口并重写 run 方法MyTimerTask(Runnable runnable,long time) {this.runnable = runnable;this.time = time + System.currentTimeMillis(); //什么时候执行任务:现在的时间 + 相对时间}public void run() {runnable.run();}
}

因为优先级队列要求元素是可排序的,所以我们需要实现 Comparable 接口并重写 compareTo 方法

public class MyTimerTask implements Comparable<MyTimerTask>{private long time; //执行任务的时间(注意这个是“绝对时间”)private Runnable runnable; //持有 Runnable 接口可以调用它的 run 方法,也可以不持有 Runnable,而是实现 Runnable 接口并重写 run 方法MyTimerTask(Runnable runnable,long time) {this.runnable = runnable;this.time = time + System.currentTimeMillis(); //什么时候执行任务:现在的时间 + 相对时间}public void run() {runnable.run();}@Overridepublic int compareTo(MyTimerTask o) {return (int) (o.time-this.time); //时间小的优先级更高}
}

补充:compareTo 方法里面是 o.time-this.time 还是 this.time - o.time,不用去刻意记忆,两种都试一下就 ok 了

测试一下:

public class TestDemo {public static void main(String[] args) throws InterruptedException {MyTimer myTimer = new MyTimer();myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("3000 ms");}},3000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("1000 ms");}},1000);}
}

在这里插入图片描述

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

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

相关文章

重生我是嵌入式大能之串口调试UART

什么是串口 串口是一种在数据通讯中广泛使用的通讯接口&#xff0c;通常我们叫做UART (通用异步收发传输器Universal Asynchronous Receiver/Transmitter)&#xff0c;其具有数据传输速度稳定、可靠性高、适用范围广等优点。在嵌入式系统中&#xff0c;串口常用于与外部设备进…

MTATLAB--一元线性回归分析

一文让你彻底搞懂最小二乘法&#xff08;超详细推导&#xff09; 在进行一元线性回归分析时&#xff0c;使用最小二乘法进行解题&#xff0c;关于最小二乘法具体看上述文章。 数据文件在文章顶部可见&#xff0c;将第一列数据作为自变量x&#xff0c;第二列数据作为应变量y。建…

3款常用的可视化工具Matplotlib、Seaborn和Pandas

大家好&#xff0c;Seaborn 是基于 Matplotlib 的扩展库&#xff0c;Pandas 的可视化功能同样也依赖于 Matplotlib。尽管二者都使用相同的底层图形库&#xff0c;但绘制图表的方法却各有千秋。本文将介绍各种柱状图的绘制&#xff0c;比较 Matplotlib、Pandas 和 Seaborn 在数据…

vulhub靶机struts2环境下的s2-032(CVE-2016-3081)(远程命令执行漏洞)

影响范围 Struts 2.3.19至2.3.20.2、2.3.21至2.3.24.1和2.3.25至2.3.28 当用户提交表单数据并验证失败时&#xff0c;后端会将用户之前提交的参数值使用OGNL表达式%{value}进行解析&#xff0c;然后重新填充到对应的表单数据中。 漏洞搭建 没有特殊要求&#xff0c;请看 (3…

EasyImage2.0 图床源码

EasyImage2.0 是一个简单图床的源码&#xff0c;它支持以下功能&#xff1a; 1. API接口 2. 登录后才能上传图片 3. 设置图片质量 4. 压缩图片大小 5. 添加文字或图片水印 6. 设定图片的宽度和高度 7. 将上传的图片转换为指定的格式 8. 限制上传图片的最小宽度和高度 …

【LangChain学习之旅】—(21)聊天客服机器人的开发(上)

【LangChain学习之旅】—(21)聊天客服机器人的开发(上) “聊天机器人”说明项目的技术实现细节技术实现步骤简述第二步:增加记忆机制第三步:增加检索机制总结“聊天机器人”说明 聊天机器人(Chatbot)是 LLM 和 LangChain 的核心用例之一,很多人学习大语言模型,学习 …

Java入门基础学习笔记19——关系运算符、逻辑运算符

关系运算符&#xff1a; 判断数据是否满足条件&#xff0c;最终会返回一个判断的结果&#xff0c;这个结果是布尔类型的值&#xff1a;true或false。 注意&#xff1a;在java中判断是否相等一定是“”&#xff0c;不要把“”写成“”&#xff0c;“”是赋值表达式。 package c…

社区新零售:家门口的便利与温暖

社区新零售&#xff1a;家门口的便利与温暖 随着都市生活节奏的加快&#xff0c;人们对于便捷、高效的生活方式有了更高的追求。社区新零售&#xff0c;作为零售业的一股新兴力量&#xff0c;正以其独特的魅力&#xff0c;悄然改变着我们的日常生活。 家门口的便利 社区新零…

嵌入式学习第三十三天!(二叉树)

1. 树的概念&#xff1a; 1. 树&#xff1a;由n个结点组成的有限集&#xff0c;有且只有一个根结点&#xff08;由根结点可以访问后继结点&#xff09;&#xff0c;其他结点只有一个前驱结点&#xff0c;但可以有多个后继结点&#xff08;一对多&#xff09;。当n 0时&#xf…

OpenAI 刚刚宣布了 “GPT-4o“ 免费用户开放、通过 API 可用

OpenAI 刚刚宣布了 “GPT-4o”。它可以通过语音、视觉和文本进行推理。 该模型速度提高了 2 倍&#xff0c;价格降低了 50%&#xff0c;比 GPT-4 Turbo 的速率限制高出了 5 倍。 它将对免费用户开放、通过 API 可用。 与 GPT-4 相比&#xff0c;GPT-4o 的速度和额外的编码能力…

揭秘APP广告:变现逻辑全解析!

在当今的移动互联网时代&#xff0c;APP广告变现已经成为了各大应用开发者的主要营收来源之一。然而&#xff0c;随着科技的发展、用户行为的变化以及广告市场趋势的演进&#xff0c;APP广告变现逻辑也正在不断地进行优化和调整。本文将基于当前市场和技术趋势&#xff0c;为大…

Proteus新手入门之初学体验

Proteus是嵌入式工程师比较喜欢用的&#xff0c;可以实现从原理图布图、代码调试到单片机与外围电路协同仿真。作为一款功能强大的电子电路仿真软件&#xff0c;Proteus为电子爱好者和工程师们提供了一个理想的平台&#xff0c;用于设计、测试和验证各种电子电路。对于初学者来…

CSS 块状元素

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

Saas详解

1. 什么是Saas SaaS&#xff08;Software-as-a-Service&#xff09;&#xff0c;简单点理解就是软件即服务&#xff0c;即通过网络提供软件服务。 在SaaS模型中&#xff0c;用户不需要在本地安装软件&#xff0c;而是通过网络&#xff08;通常是浏览器&#xff09;访问应用程…

LeetCode算法题:49. 字母异位词分组(Java)

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", …

答辩PPT自述稿如何准备?笔灵AI答辩PPT,自动生成演讲稿

很多快要毕业的同学在做答辩PPT的时候总是感觉毫无思路&#xff0c;一窍不通。但这并不是你们的错&#xff0c;对于平时没接触过相关方面&#xff0c;第一次搞答辩PPT的人来说&#xff0c;这是很正常的一件事。一个好的答辩PPT可以根据以下分为以下几部分来写。 1.研究的背景和…

试试这四个AI论文工具和降重技术,低成本高回报

在科研领域&#xff0c;AI写作工具如同新一代的科研利器&#xff0c;它们能够极大提高文献查阅、思路整理和表达优化的效率&#xff0c;本质上促进了科研工作的进步。AI写作工具不仅快速获取并整理海量信息&#xff0c;还帮助我们精确提炼中心思想&#xff0c;显著提升论文写作…

研发管理-选择研发管理系统-研发管理系统哪个好

选择研发管理系统-研发管理系统哪个好 选择研发管理系统时&#xff0c;并没有一个绝对的“最好”的系统&#xff0c;因为每个企业的需求和情况都是独特的。然而&#xff0c;我可以向您介绍一些在市场上广受欢迎且功能强大的研发管理系统&#xff0c;供您参考&#xff1a; 1、彩…

MathType7.9中文官方最新破解汉化版无需许可证激活码

MathType是一个功能强大的数学公式编辑器&#xff0c;它能够帮助用户轻松地创建、编辑和排版各种数学公式。无论是学生、教师还是科研人员&#xff0c;都可以从MathType的丰富功能中受益。本文将为您详细介绍MathType的主要功能和使用方法&#xff0c;帮助您更好地利用这个工具…

web网页录音(recorder.js)并上传后端语音转文字(Vosk)

我是一个后端开发人员&#xff0c;现在都快进化成全栈了。操了&#xff0c;是谁有好的项目让我跳跳槽&#xff0c;转转行吧 写在前面&#xff0c;很重要 这是官方文档的说明 翻译如下&#xff1a; 我们有两种型号-大型号和小型号&#xff0c;小型号非常适合在移动应用程序上执…