【JavaEE】多线程案例 - 定时器
作者主页:paper jie_博客
本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。
本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。
其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等
内容分享:本期将会分享多线程案例 - 定时器
目录
什么是定时器
Java标准库中的定时器 - Timer
自定义一个定时器
定时器的组成
描述类MyTask
实现MyTask的比较
MyTimer类的构架
schedule方法
内置线程
线程安全与wait等待
具体代码
代码执行流程
什么是定时器
定时器是我们程序猿来软件开发中一个很重要的组件.它的作用就是和闹钟一样. 当达到一个设定的时间后,就需要去执行某段指定的代码.定时器在我们实际开发中特别常见.比如一款游戏需要联网才能使用,要是在1秒之内没有数据返回给服务器,这时定时器就会发挥作用,断开与网络的连接然后尝试重连.
Java标准库中的定时器 - Timer
在我们Java标准库中就内置了一个Timer类,他就是定时器. 它里面有一个核心方法schedule就是用来注册任务的.
schedule里面有两个参数. 一个是时间到了需要执行的代码, 第二个是需要等待的时间,单位是毫秒.
public class ThreadDemo11 {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 1000");}}, 1000);}
}
自定义一个定时器
定时器的组成
这里用一个MyTimer类来表示定时器
1) 需要一个存放任务的优先级队列PriorityQueue
2) 需要一个MyTask类来描述任务
3) 这些任务是需要比较时间的,MyTask类需要实现Comparable接口
4) 需要定义一个内置线程来不断扫描任务观察时间到了没
5) 需要实现核心方法schedule来注册任务
描述类MyTask
Task这个类用来描述任务,里面包含一个Runnable对象和一个time时间戳. 需要执行的代码会通过传参的形式给到Runnable.
class MyTask3 {//private long time;private Runnable runnable = null;public MyTask3(Runnable runnable, long delay) {this.runnable = runnable;//需要执行的时刻this.time = System.currentTimeMillis() + delay;}//获取时间public long getTime() {return time;}//获取需要执行的代码public void run() {runnable.run();}}
实现MyTask的比较
因为Mytask是描述任务,而这些任务需要放到优先级队列中比较,就需要实现Comparable或者比较器.这里我们实现Comparable接口.
class MyTask3 implements Comparable<MyTask3>{//private long time;private Runnable runnable = null;public MyTask3(Runnable runnable, long delay) {this.runnable = runnable;//需要执行的时刻this.time = System.currentTimeMillis() + delay;}//获取时间public long getTime() {return time;}//获取需要执行的代码public void run() {runnable.run();}//比较时间快慢方法@Overridepublic int compareTo(MyTask3 o) {return (int)(this.time - o.time);}
}
MyTimer类的构架
这里最核心的就是priorityQueue这个优先级队列,用它来存放我们的任务. 所对象为我们后面起到一个加锁的作用.
class MyTimer3 {//用优先级队列来存放任务private PriorityQueue<MyTask3> priorityQueue = new PriorityQueue<>();//锁对象private Object blocker = new Object();public void schedule(Runnable runnable, long time) {//核心方法}
}
schedule方法
这里我们在核心方法schedule中创建出一个任务,再将这个任务放入优先级队列中.
public void schedule(Runnable runnable, long time) {//创建一个任务MyTask3 myTask3 = new MyTask3(runnable, time);//将创建的任务放入优先级队列中priorityQueue.offer(myTask3);}
内置线程
这里将内置线程放入构造方法中,当这个类一创建就开始执行. 这里通过while循环来不断扫描.
//内置线程public MyTimer3() {//创建一个线程Thread t = new Thread(() -> {//通过while来不断扫描while(true) {//判断优先级队列是不是空的if(priorityQueue.isEmpty()) {//为空就等待//continue;}//当优先级队列中有任务时,取出任务MyTask3 myTask3 = priorityQueue.peek();//当前时间long time = System.currentTimeMillis();//如果到时间了就执行if(time >= myTask3.getTime()) {myTask3.run();priorityQueue.take();}else {//时间没到等待//continue;}}});t.start();}
线程安全与wait等待
这里发现schedule方法和构造方法都会有对于priorityQueue优先级队列的读和修改,这里可能就会出现线程安全问题,我们就需要为他们加上锁. 为空时我们就通过wait方法等待,等调用schedule方法使用notify唤醒它. 当有元素时但时间没到也是使用wait有时间的等待,时间到了就解除等待.
public void schedule(Runnable runnable, long time) {synchronized (blocker) {//创建一个任务MyTask3 myTask3 = new MyTask3(runnable, time);//将创建的任务放入优先级队列中priorityQueue.offer(myTask3);//通过notify来唤醒扫描线程blocker.notify();}}//内置线程public MyTimer3() {//创建一个线程Thread t = new Thread(() -> {//通过while来不断扫描while(true) {//加锁synchronized (blocker) {try {//判断优先级队列是不是空的if(priorityQueue.isEmpty()) {//为空就等待blocker.wait();}//当优先级队列中有任务时,取出任务MyTask3 myTask3 = priorityQueue.peek();//当前时间long time = System.currentTimeMillis();//如果到时间了就执行if(time >= myTask3.getTime()) {myTask3.run();priorityQueue.poll();}else {//时间没到等待 通过wait等待 有时间的等待.blocker.wait(myTask3.getTime() - time);}}catch(InterruptedException o) {o.printStackTrace();}}}});//启动线程t.start();}
具体代码
class MyTask3 implements Comparable<MyTask3>{//private long time;private Runnable runnable = null;public MyTask3(Runnable runnable, long delay) {this.runnable = runnable;//需要执行的时刻this.time = System.currentTimeMillis() + delay;}//获取时间public long getTime() {return time;}//获取需要执行的代码public void run() {runnable.run();}//比较时间快慢方法@Overridepublic int compareTo(MyTask3 o) {return (int)(this.time - o.time);}
}class MyTimer3 {//用优先级队列来存放任务private PriorityQueue<MyTask3> priorityQueue = new PriorityQueue<>();//所对象private Object blocker = new Object();//核心方法public void schedule(Runnable runnable, long time) {synchronized (blocker) {//创建一个任务MyTask3 myTask3 = new MyTask3(runnable, time);//将创建的任务放入优先级队列中priorityQueue.offer(myTask3);//通过notify来唤醒扫描线程blocker.notify();}}//内置线程public MyTimer3() {//创建一个线程Thread t = new Thread(() -> {//通过while来不断扫描while(true) {//加锁synchronized (blocker) {try {//判断优先级队列是不是空的if(priorityQueue.isEmpty()) {//为空就等待blocker.wait();}//当优先级队列中有任务时,取出任务MyTask3 myTask3 = priorityQueue.peek();//当前时间long time = System.currentTimeMillis();//如果到时间了就执行if(time >= myTask3.getTime()) {myTask3.run();priorityQueue.poll();}else {//时间没到等待 通过wait等待 有时间的等待.blocker.wait(myTask3.getTime() - time);}}catch(InterruptedException o) {o.printStackTrace();}}}});//启动线程t.start();}
}
代码执行流程
相关文章:

【JavaEE】多线程案例 - 定时器
作者主页:paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造&…...

网络小测------
使用软件PT7.0按照上面的拓扑结构建立网络,进行合理配置,使得所有计算机之间能够互相通信。并且修改各交换机的系统名称为:学号_编号,如你的学号为123,交换机Switch0的编号为0,则系统名称为123_0࿱…...

基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里
【JDK安装】 1.首先下载一个JDK版本 官网地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载1.8版本,用红框标注出来了: 也许有的同学看到没有1.8版本,你可以随便下载一个linux的…...

04-Nacos中负载均衡规则的配置
负载均衡规则 同集群优先 默认的ZoneAvoidanceRule实现并不能根据同集群优先的规则来实现负载均衡,Nacos中提供了一个实现叫NacosRule可以优先从同集群中挑选服务实例 当服务消费者在本地集群找不到服务提供者时也会去其他集群中寻找,但此时会在服务消费者的控制台报警告 第…...

Kotlin 中的 `use` 关键字:优化资源管理(避免忘记inputStream.close() ?)
在 Android开发中,正确且高效地管理资源是至关重要的。use 关键字在 Kotlin 中为资源管理提供了一个简洁且强大的解决方案。它主要用于自动管理那些需要关闭的资源,比如文件、网络连接等。 一、use 关键字的工作原理 🤖 use 是一个扩展函数…...

时序预测 | Python实现GRU-XGBoost组合模型电力需求预测
时序预测 | Python实现GRU-XGBoost组合模型电力需求预测 目录 时序预测 | Python实现GRU-XGBoost组合模型电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前…...

扁平化菜单功能制作
网页效果: HTML部分: <body><ul class"nav"><li><a href"javascript:void(0);">菜单项目一</a><ul><li>子菜单项01</li><li>子菜单项02</li><li>子菜单项03<…...

网络基础——路由协议及ensp操作
目录 一、路由器及路由表 1.路由协议: 2.路由器转发原理: 3.路由表: 二、静态路由优缺点及特殊静态路由默认路由 1.静态路由的优缺点: 2.下一跳地址 3.默认路由 三、静态路由配置 四、补充备胎 平均负载 五、补充&…...

Python-折线图可视化
折线图可视化 1.JSON数据格式2.pyecharts模块介绍3.pyecharts快速入门4.创建折线图 1.JSON数据格式 1.1什么是JSON JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据JSON本质上是一个带有特定格式的字符串 1.2主要功能json就是一种在各个编程语言中流…...

C++类与对象 (上)
目录 前言: 类和对象的理解 类的引入 类的定义与使用方式 访问限定符 类的两种定义方式 成员变量的命名规则 类的作用域 类的实例化 类对象模型 计算类对象的大小 类对象的存储方式 this指针 前言: C语言是面向过程的,关注的是过…...

no module named ‘xxx‘
目录结构如下 我想在GCNmodel的model里引入layers的GraphConvolution:from GCNmodel.layers import GraphConvolution,但这样却报错no module named GCNmodel,而且用from layers import GraphConvolution也不行。然后用sys.path.appen(xxx)…...

Go实现MapReduce
背景 当谈到处理大规模数据集时,MapReduce是一种备受欢迎的编程模型。它最初由Google开发,用于并行处理大规模数据以提取有价值的信息。MapReduce模型将大规模数据集分解成小块,然后对这些小块进行映射和归约操作,最终产生有用的…...

Axure的交互样式和情形
Axure的交互样式和情形 交互样式 Axure是一个流行的原型设计工具,它允许您创建交互式原型,模拟应用程序或网站的功能和用户界面。在Axure中,您可以设置各种交互样式来使原型更加生动和真实。 链接触发器:通过给一个元素添加链接…...

Mybatis在新增某个数据后,如何获取新增数据的id
在某些业务中,我们在新增一条数据之后,需要拿到这条数据的id来对这条数据进行后续的一个操作,如何拿取id呢? 使用的是<insert> 中的useGeneratedKeys 和 keyProperty 两个属性 1.在Mybatis Mapper文件中添加属性 “useGene…...

12.4~12.14概率论复习与相应理解(学习、复习、备考概率论,这一篇就够了)
未分配的题目 概率计算(一些转换公式与全概率公式)与实际概率 ,贝叶斯 一些转换公式 相关性质计算 常规,公式的COV与P 复习相关公式 计算出新表达式的均值,方差,再套正态分布的公式 COV的运算性质 如…...

关于多重背包的笔记
多重背包可以看作01背包的拓展, 01背包是选或者不选。多重背包是选0个一直到选s个。 for (int i 1; i < n; i) {for (int j m; j > w[i]; --j){f[j] max(f[j], f[j - 1*w[i]] 1*v[i], f[j - 2*w[i]] 2*v[i],...f[j - s*w[i]] s*v[i]);} } 由上述伪代码…...

如何使用 Java 的反射
如何使用 Java 的反射? 通过一个全限类名创建一个对象 Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver 类已经被加载到 jvm 中,并且完成了类的初始化工作就行了 类名.class; 获取 Class<?> clz 对象对…...

PLC-Recorder V3 修改服务器和客户端通讯端口的方法
PLC-Recorder V3是服务器和客户端的架构,他们之间用TCP通讯。如果客户端无法与服务器建立连接(重启也无效,并且确保没有老版本的PLC-Recorder在运行),则可能是端口被占用了。这时候需要修改他们之间的通讯端口…...

libevent服务GET/POST的简单使用
目录 1、前言2、测试demo2.1、目录结构2.2、 测试源码2.2.1、http_server.cpp2.2.2、 http_server.h 2.3、 编译2.4、 运行结果2.4.1、测试POST2.4.2 、测试GET请求 1、前言 项目开发中经常需要使用到私有协议和Qt,Android等GUI前端通信,比较常用的使用POST和GET方式…...

MySQL 系列:注意 ORDER 和 LIMIT 联合使用的陷阱
文章目录 前言背后的原因ORDER BY 排序列存在相同值时返回顺序是不固定的LIMIT 和 ORDER BY 联合使用时的行为ORDER BY 或 GROUP BY 和 LIMIT 联合使用优化器默认使用有序索引 如何解决其它说明个人简介 前言 不知道大家在在分页查询中有没有遇到过这个问题,分页查…...

通过实例理解OAuth2授权
在之前的《通过实例理解Go Web身份认证的几种方式[1]》和《通过实例理解Web应用授权的几种方式[2]》两篇文章中,我们对Web应用身份认证(AuthN)和授权(AuthZ)的几种方式做了介绍并配以实例增强理解。 在现实世界中,还有一大类的认证与授权是在前面的文章中…...

MATLAB2022安装下载教程
安装包需从夸克网盘自取: 链接:https://pan.quark.cn/s/373ffc9213a1 提取码:N7PW 1.将安装包解压 2.以管理员的身份运行文件夹中的setup文件 3.点击高级选项--->我有文件安装密钥 4. 选择【是】,进入下一步 5.输入密钥 0532…...

从零开始搭建Go语言开发环境
https://www.liwenzhou.com/posts/Go/install_go_dev/ “go 命令现在默认在模块感知模式下构建包,即使没有 go.mod 存在也是如此。 “您可以将 GO111MODULE 设置为 auto,仅当当前目录或任何父目录中存在 go.mod 文件时,才能启用模块感知模式…...

vite+vue3+ts+tsx+ant-design-vue项目框架搭建
参与公司项目开发一段时间了,项目用到了很多新的技术(vite,vue3,ts等等),但是框架都是别人搭好的,然后就想说如果是自己的话,会从零搭建一个吗,于是就有了这篇文章。 目录 一、涉及到的相关依…...

【5G PHY】5G小区类型、小区组和小区节点的概念介绍
博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…...

创建个人网站(一)从零开始配置环境,搭建项目
目录 前言配置环境前端后端遇到的问题1.安装了nvm和node,vscode没反应2.安装完脚手架之后vue指令不存在 vscode插件(以后遇到好的会添进去) 前言 从刚开始学前端的html直到现在前后端都有在开发,我一直都有一个想法,就…...

fripside - promise lrc
[ti:promise] [ed:2] [rt:20] [ml:0|0] [00:05.172]words:Satoshi Yaginuma, Shinichiro Yamashita [00:09.664]music&arrangement:Satoshi Yaginuma, Shigetoshi Yamada [00:14.565]PCゲーム「ENGAGE LINKS」 (Alcot) エンディングテーマ [00:20.000] [00:46.442]朝の陽射…...

网络连接和协议
网络连接是通过一系列协议来实现的,其中TCP/IP协议和HTTP协议是其中两个关键的协议。 1. **TCP/IP协议:** - TCP/IP(Transmission Control Protocol/Internet Protocol)是一组用于在互联网上传输数据的协议。它是一个层次化的…...

MySQL数据库,表的增量备份与恢复
1. 从物理与逻辑的角度 数据库备份可以分为物理备份和逻辑备份。物理备份是对数据库操作系统的物理文件(如数据 文件,日志文件等)的备份。这种类型的备份适用于在出现问题时需要快速恢复的大型重要数据库。 物理备份又可以分为冷备份…...

13.Spring 整合 Kafka + 发送系统通知 + 显示系统通知
目录 1.Spring 整合 Kafka 2.发送系统通知 2.1 封装事件对象 2.2 开发事件的生产者和消费者 2.3 触发事件:在评论、点赞、关注后通知编辑 3.显示系统通知 3.1 通知列表 3.1.1 数据访问层 3.1.2 业务层 3.1.3 表现层 3.2 开发通知详情 3.2.1 开发数据…...