【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();}
}

代码执行流程


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

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

相关文章

深度学习项目实战:垃圾分类系统

简介&#xff1a; 今天开启深度学习另一板块。就是计算机视觉方向&#xff0c;这里主要讨论图像分类任务–垃圾分类系统。其实这个项目早在19年的时候&#xff0c;我就写好了一个版本了。之前使用的是python搭建深度学习网络&#xff0c;然后前后端交互的采用的是java spring …

python学习2

大家好&#xff0c;这里是七七&#xff0c;这次学习的例子是一个数据清洗代码。完整代码在最后。 开始这次的内容 目录 代码一 代码二 代码三 代码四 全部代码 代码一 xlsx_file data/附件1.xlsx df_1 pd.read_excel(xlsx_file) xlsx_file data/附件2.xlsx df pd.re…

workflow系列教程(4)Parallel并联任务流

往期教程 如果觉得写的可以,请给一个点赞关注支持一下 观看之前请先看,往期的博客教程,否则这篇博客没办法看懂 workFlow c异步网络库编译教程与简介 C异步网络库workflow入门教程(1)HTTP任务 C异步网络库workflow系列教程(2)redis任务 workflow系列教程(3)Series串联任务流…

一个 tomcat 下如何部署多个项目?附详细步骤

一个tomcat下如何部署多个项目&#xff1f;Linux跟windows系统下的步骤都差不多&#xff0c;以下linux系统下部署为例。windows系统下部署同理。 1 不修改端口&#xff0c;部署多个项目 清楚tomcat目录结构的应该都知道&#xff0c;项目包是放在webapps目录下的&#xff0c;那…

【SpringBoot零基础入门到项目实战①】解锁现代Java开发之门:深度探究Spring Boot的背景、目标及选择理由

文章目录 引言Spring Boot的背景和目标背景目标 为什么选择Spring Boot1. 简化配置2. 内嵌式容器3. 生态系统支持4. 大量的Starter5. 广泛的社区支持6. 适用于微服务架构7. 丰富的扩展机制 实例演示创建一个简单的Spring Boot应用 拓展与深入学习1. Spring Boot Actuator2. Spr…

MySQL数据库,表的增量备份与恢复

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

MySQL进阶|MySQL中的事务(一)

文章目录 数据库事务MySQL中的存储引擎InnoDB存储引擎架构什么是事务事务的状态总结 数据库事务 MySQL 事务主要用于处理操作量大&#xff0c;复杂度高的数据。比方我想要删除一个用户&#xff08;销户&#xff09;以及这个用户的个人信息、订单信息以及其他信息&#xff0c;这…

遗传算法应用-- 栅格法机器人路径规划

文章目录 一、遗传算法1.1 编码与解码1.2 选择算子-轮盘赌法1.3 交叉算子1.4 变异算子1.5 遗传算法流程1.6 基于遗传算法的栅格法机器人路径规划 二、采用模拟退火算法改善适应度函数 一、遗传算法 遗传算法 (Genetic AIgorithm, 简称 GA)起源于对生物系统所进行的计算机模拟研…

王道考研--》单链表课后习题C语言代码实现(冲刺)

考研是许多计算机科学专业学生追求高学历、寻求更好就业前景的途径。在考研过程中&#xff0c;数据结构是一个非常重要的科目&#xff0c;而代码实现题更是其中的难点之一。在这篇文章中&#xff0c;我们将探讨如何通过实现数据结构代码问题来提升考研成绩。无论您是否有编程经…

Linux:TCP 序列号简介

文章目录 1. 前言2. 什么是 TCP 序列号&#xff1f;3. TCP 序号 的 初始值设置 和 后续变化过程3.1 三次握手 连接建立 期间 客户端 和 服务端 序号 的 变化过程3.1.1 客户端 socket 初始序号 的 建立3.1.2 服务端 socket 初始序号 的 建立3.1.3 客户端 socket 接收 服务端 SAC…

2024年最免费的DAW混音编曲FL Studio21.2.中文版下载

FL Studio 简称FL&#xff0c;全称Fruity Loops Studio&#xff0c;因此国人习惯叫它"水果"。目前最新版本是FL Studio21.1.1.3750版本&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破…

欧睿 × 和鲸:联合打造 AI 中台赋能企业数字化转型,大幅提升模型产品研发效率

近年来&#xff0c;在泛零售及快消行业&#xff0c;由于市场格局越发瞬息万变、消费场景愈加错综复杂&#xff0c;以机器学习算法、人工智能模型代替纯人脑人工完成商品计划、运营、供应链管理已逐渐成为主流。 oIBP 欧睿数据&#xff08;下简称“欧睿”&#xff09;是国内领先…