【JaveEE】多线程之定时器(Timer)
目录
1.定时器的定义
2.标准库中的定时器
2.1构造方法
2.2成员方法
3.模拟实现一个定时器
schedule()方法
构造方法
4.MyTimer完整代码
1.定时器的定义
定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定好的代码.
定时器是一种实际开发中非常常用的组件.类似于下方的场景就需要用到定时器:
- 比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.
- 比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自动删除).
2.标准库中的定时器
2.1构造方法
名称 | 作用 |
---|---|
Timer() | 创建一个新的定时器 |
Timer(boolean isDaemon) | 创建一个新的定时器,其相关线程可以指定为 run as a daemon |
Timer(String name) | 创建一个新的定时器,其相关线程具有指定的名称 |
Timer(String name, boolean isDaemon) | 创建一个新的定时器,其相关线程具有指定的名称,可指定为run as a daemon |
2.2成员方法
方法名 | 作用 |
void cancel() | 终止此计时器,丢弃任何当前计划的任务。 |
int purge() | 从该计时器的任务队列中删除所有取消的任务。 |
void schedule(TimerTask task, Date time) | 在指定的时间安排指定的任务执行。 |
void schedule(TimerTask task, Date firstTime, long period) | 从指定 的时间开始 ,对指定的任务执行重复的 固定延迟执行 。 |
void schedule(TimerTask task, long delay) | 在指定的延迟之后安排指 定的任务执行。 |
void schedule(TimerTask task, long delay, long period) | 在指定 的延迟之后开始 ,重新 执行 固定延迟执行的指定任务。 |
void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) | 从指定的时间 开始 , 对指定的任务执行重复的 固定速率执行 。 |
void scheduleAtFixedRate(TimerTask task, long delay,long period) | 在指定的延迟之后 开始 , 重新执行 固定速率的指定任务。 |
- 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule 。
- schedule 包含两个参数. 第一个参数指定即将要执行的任务代码(Mytask), 第二个参数指定多长时间之后执行 (单位为毫秒)。
schedule方法参数列表: void schedule(TimerTask task, long delay)
作用:在指定的延迟之后安排指定的任务执行。
实现一个简单的定时器使用:
import java.util.Timer;
import java.util.TimerTask;public class testDemo1 {public static void main(String[] args) {Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello4");}},4000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello3");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello2");}},2000);System.out.println("hell01");}
}
上方代码,是让在定时器中执行4个任务,分别等待时间4s,3s,2s,1s,打印内容。
运行结果如下:
观察结果,定时器通过对延迟时间的排序完成了打印,再仔细看,程序并没有停止,什么时候程序不会停止呢?就是前台线程没有执行完的时候程序不会停止,也就是说定时器中的创建的线程是前台线程,并且在完成任务后,不会立即停止。
3.模拟实现一个定时器
定时器的主要构造内容:
public class MyTimer{
//1.一个优先级阻塞队列
//2.一个内部类Mytask(服务于schedule方法)
//3.schedule方法
//4.一个构造方法
//5.一个锁
}
定时器中核心数据结构是优先级阻塞队列(PriorityBlockingQueue),它能够帮助我们判断谁先执行,谁后执行。
schedule()方法
schedule()方法是定时器的核心方法,它相当于一个时间表,安排每一个任务的时间。
该方法有两个参数:1.runnable(任务) 2.delay(延迟时间)
因为需要将两个参数同时加入到 优先级阻塞队列(PriorityBlockingQueue)当中,因此我们需要将其进行封装一下,代码如下:
class MyTask implements Comparable<MyTask>{public Runnable runnable;public long time;public MyTask(Runnable runnable, long time) {this.runnable = runnable;this.time =System.currentTimeMillis()+time;}@Overridepublic int compareTo(MyTask o) {return (int)(this.time-o.time);}
}
在使用延迟时间时,我们现在使用绝对时间来记录,这里使用到了时间戳,并且实现Comparable<>接口,他的目的是告诉阻塞队列,根据时间判断优先执行哪一个任务。
进行来看schedule方法的实现:
public void schedule(Runnable runnable,long delay) {MyTask task=new MyTask(runnable,delay);queue.put(task);//来新任务了,就叫醒线程synchronized (locker){locker.notify();}}
代码解读是:构造一个任务,并且设定它的延迟时间,将任务加入到优先级阻塞队列,下方的notify方法配合构造方法中的wait使用(下方会有解读)。
构造方法
代码实现如下:
public MyTimer() {Thread t=new Thread(()->{while (true) {synchronized (locker) {try {MyTask cur = queue.take();long curTime = System.currentTimeMillis();if (curTime <= cur.time) {//没到时间queue.put(cur);locker.wait(cur.time - curTime);} else {//时间到了cur.runnable.run();}} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();}
代码解读:
我们先取出队列的队首元素,在调用出现在的时间戳,判断队首元素是否达到时间了,因为优先级阻塞队列里面没有peek方法,我们每次比较都必须将队首元素拿出来,若没有达到指定时间,我们需要再将队首元素再次塞进队伍当中,塞回去之后,若时间到了,就执行这个任务的run方法。
在判断后,时间没到时,我们不能再一直进行判断时间,因为这个cpu即没干任何事,也没有得到休息(cpu忙等),这时我们就可以使用wait方法,让cpu先将资源释放了,等待唤醒就行了,只要参数中的时间到了或者有需要比现在任务优先级更高的任务需要执行,就让他先执行。
4.MyTimer完整代码
import java.util.concurrent.PriorityBlockingQueue;
//没个任务都有一个需要做的事
class MyTask implements Comparable<MyTask>{public Runnable runnable;long time;public MyTask(Runnable runnable, long time) {this.runnable = runnable;this.time =System.currentTimeMillis()+time;}@Overridepublic int compareTo(MyTask o) {return (int)(this.time-o.time);}
}
public class MyTimer {//核心数据结构,优先级阻塞队列private PriorityBlockingQueue<MyTask> queue=new PriorityBlockingQueue<>();private Object locker=new Object();public void schedule(Runnable runnable,long delay) {MyTask task=new MyTask(runnable,delay);queue.put(task);//来新任务了,就叫醒线程synchronized (locker){locker.notify();}}public MyTimer() {Thread t=new Thread(()->{while (true) {synchronized (locker) {try {MyTask cur = queue.take();long curTime = System.currentTimeMillis();if (curTime <= cur.time) {//没到时间queue.put(cur);locker.wait(cur.time - curTime);} else {//时间到了cur.runnable.run();}} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();}
}
写在最后:
以上就是本文全部内容,如果对你有所帮助,希望能留下你的点赞+关注,我会更加努力的更新内容!非常感谢🧡🧡🧡
若本篇文章有错误的地方,欢迎大佬们指正!
相关文章:

【JaveEE】多线程之定时器(Timer)
目录 1.定时器的定义 2.标准库中的定时器 2.1构造方法 2.2成员方法 3.模拟实现一个定时器 schedule()方法 构造方法 4.MyTimer完整代码 1.定时器的定义 定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指…...

【理论推导】变分自动编码器 Variational AutoEncoder(VAE)
变分推断 (Variational Inference) 变分推断属于对隐变量模型 (Latent Variable Model) 处理的一种技巧,其概率图如下所示 我们将 X{x1,...xN}X\{ x_1,...x_N \}X{x1,...xN} 看作是每个样本可观测的一组数据,而将对应的 Z{z1,...,zN}Z\{z_1,...,z_N…...

【哈希表:哈希函数构造方法、哈希冲突的处理】
预测未来的最好方法就是创造它💦 目录 一、什么是Hash表 二、Hash冲突 三、Hash函数的构造方法 1. 直接定址法 2. 除余法 3. 基数转换法 4. 平方取中法 5. 折叠法 6. 移位法 7. 随机数法 四、处理冲突方法 1. 开放地址法 • 线性探测法 …...

HTML5 应用程序缓存
HTML5 应用程序缓存 使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本。这意味着,你可以在没有网络连接的情况下进行访问。 什么是应用程序缓存(Application Cache)? HTML5 引…...

全国计算机等级考试三级网络技术选择题考点
目录 第一章 网络系统结构与设计的基本原则 第二章 中小型网络系统总体规划与设计方法 第三章 IP地址规划技术 第四章 路由设计基础 第五章 局域网技术基础应用 第六/七章 交换机/路由器及其配置 第八章 无线局域网技术 第九章 计算机网络信息服务系统的安装与…...

Python和VC代码实现希尔伯特变换(Hilbert transform)
文章目录前言一、希尔伯特变换是什么?二、VC中的实现原理及代码示例三、用Python代码实现总结前言 在数学和信号处理中,**希尔伯特变换(Hilbert transform)**是一个对函数产生定义域相同的函数的线性算子。 希尔伯特变换在信号处…...

嵌入式C语言语法概述
1.gcc概述 GCC全称是GUN C Compiler 随着时代的发展GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection gcc的作用相当于翻译官,把程序设计语言翻译成计算机能理解的机器语言。 (1)gcc -o gcc -o (其…...

蓝桥杯第19天(Python)(疯狂刷题第3天)
题型: 1.思维题/杂题:数学公式,分析题意,找规律 2.BFS/DFS:广搜(递归实现),深搜(deque实现) 3.简单数论:模,素数(只需要…...

【数据库连接,线程,ThreadLocal三者之间的关系】
一、数据库连接与线程的关系 在实际项目中,数据库连接是很宝贵的资源,以MySQL为例,一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200,再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议&…...

java 虚拟股票交易系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目
一、源码特点 JSP 虚拟股票交易系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统采用serlvetdaobean,系统具有完整的源代码和数据库,系统主要采用 B/S模式开发。 java 虚拟股票交易系统Myeclips…...

spring如何开启允许循环依赖
如何解决spring循环依赖 在Spring框架中,allowCircularReferences属性是用于控制Bean之间的循环依赖的。循环依赖是指两个或多个Bean之间相互依赖的情况,其中一个Bean依赖于另一个Bean,同时另一个Bean又依赖于第一个Bean。 allowCircularRe…...

jenkins+sonarqube+自动部署服务
一、jenkins 配置Pipeline 二、新建共享库执行脚本 共享库可以是一个普通的gitlab项目,目录结构如下 三、添加到共享库 Jenkins Dashboard–>系统管理–>系统配置–>Global Pipeline Libraries Name: 共享库名称,自定义即可; Defa…...

【算法系列之动态规划III】背包问题
背包问题 01背包指的是物品只有1个,可以选也可以不选。完全背包是物品有无数个,可以选几个也可以不选。 二维数组01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次&…...

MONAI-LayerFactory设计与实现
LayerFactory 用于创建图层的工厂对象,这使用给定的工厂函数来实际产生类型或构建可调用程序。这些函数是通过名称来参考的,可以在任何时候添加。 用到的关键技术点: 装饰器(Decorators), 例如:property装饰器,创建…...

Thinkphp 6.0路由的定义
本节课我们来了解一下路由方面的知识,然后简单的使用一下路由的功能。 一.路由简介 1. 路由的作用就是让 URL 地址更加的规范和优雅,或者说更加简洁; 2. 设置路由对 URL 的检测、验证等一系列操作提供了极大的便利性; …...

Kafka系列之:深入理解Kafka集群调优
Kafka系列之:深入理解Kafka集群调优 一、Kafka硬件配置选择二、Kafka内存选择三、CPU选择四、网络选择五、生产者调优六、broker调优七、消费者调优八、Kafka总体调优一、Kafka硬件配置选择 服务器台数选择: 2 * (生产者峰值生产速率 * 副本数 / 100) + 1磁盘选择: Kafka…...

creator-泄漏检测之资源篇
title: creator-泄漏检测之资源篇 categories: Cocos2dx tags: [creator, 优化, 泄漏, 内存] date: 2023-03-29 14:48:48 comments: false mathjax: true toc: true creator-泄漏检测之资源篇 前篇 资源释放 - https://docs.cocos.com/creator/manual/zh/asset/release-manager…...

【DevOps】Jenkins 运行任务时遇到 FATAL:Unable to produce a script file 报错(已解决)
文章目录一、问题描述二、定位原因三、解决方案四、其他方案五、总结关键词: Jenkins、Unable to produce a script file、UnmappableCharacterException、IOException: Failed to create a temp file on一、问题描述 由于使用的 Jenkins 存在安全漏洞(…...

Web前端
WEB前端 HTMLCSSJavaScriptjQuery(js框架)Bootstrap(CSS框架)AJAXJSON 文章目录 WEB前端WEB前端三大核心技术Web开发工具文本编辑器集成开发环境(IDE)浏览器选择HTML什么是 HTML?HTML版本变迁HTML-HelloWorldHTML 文档 = 网页HTML 标签属性(Attribute)HTML 常用标签...

资源操作:Resources
文章目录1. Spring Resources概述1.2 Resource 接口1.3 Resource的实现类1.3.1 UrlResource访问网络资源1.3.2 ClassPathResource访问类路径下资源1.3.3 FileSystemResource访问文件系统资源1.3.4 ServletContextResource1.3.5、InputStreamResource1.3.6、ByteArrayResource1.…...

GDB调试的学习
很早就想在好好学一学gdb了,正好最近学算法(以前一直以为干硬件不需要什么特别厉害的算法,结果现在卷起来了。大厂面试题也有复杂一些的算法了) 下面的这些命令是别的博主总结的 GDB 调试过程_gdb调试过程_麷飞花的博客-CSDN博客…...

熵值法综合评价分析流程
熵值法综合评价分析流程 一、案例背景 当前有一份数据,是各品牌车各个维度的得分情况,现在想要使用熵值法进行综合评价,得到各品牌车的综合得分,从而进行车型优劣对比,为消费者提供购车依据。 数据如下(数…...

使用Python Pandas库操作Excel表格的技巧
在数据分析和处理中,我们经常需要对Excel表格进行操作。Python Pandas库提供了丰富的API来读取、写入、修改Excel表格。本文将介绍如何使用Python Pandas库操作Excel表格,包括向Excel表格添加新行、创建Excel表格等。 1.向Excel表格添加新行 下面是一个…...

LeetCode练习七:动态规划上:线性动态规划
文章目录一、 动态规划基础知识1.1 动态规划简介1.2 动态规划的特征1.2.1 最优子结构性质1.2.2 重叠子问题性质1.2.3 无后效性1.3 动态规划的基本思路1.4 动态规划基础应用1.4.1 斐波那契数1.4.2 爬楼梯1.4.3 不同路径1.5 个人总结二、记忆化搜索2.1 记忆化搜索简介2.2 记忆化搜…...

基于正点原子F407开发版和SPI接口屏移植touchgfx完整教程(一)
一、相关软件包安装 1、打开cubemx包管理器 2、安装F4软件包 3、安装touchgfx软件包 二、工程配置 1、新建工程 2、sys配置 3、rcc配置 4、crc配置 5、添加touchgfx软件包 6、配置touchgfx软件包 将width和height改为自己屏幕尺寸 7、生成工程 三、代码修改 1、将屏幕相关驱…...

Linux--进程间通信
前言 上一篇相关Linux文章已经时隔2月,Linux的学习也相对于来说是更加苦涩;无妨,漫漫其修远兮,吾将上下而求索。 下面该片文章主要是对进程间通信进行介绍,还对管道,消息队列,共享内存,信号量都…...

hadoop伪分布式集群搭建
基于hadoop 3.1.4 一、准备好需要的文件 1、hadoop-3.1.4编译完成的包 链接: https://pan.baidu.com/s/1tKLDTRcwSnAptjhKZiwAKg 提取码: ekvc 2、需要jdk环境 链接: https://pan.baidu.com/s/18JtAWbVcamd2J_oIeSVzKw 提取码: bmny 3、vmware安装包 链接: https://pan.baidu…...

Qt 中的信息输出机制:QDebug、QInfo、QWarning、QCritical 的简单介绍和用法
Qt 中的信息输出机制介绍QDebug在 Qt 中使用 qDebug输出不同类型的信息浮点数:使用 %!f(MISSING) 格式化符号输出浮点数布尔值:使用 %! (MISSING)和 %! (MISSING)格式化符号输出布尔值对象:使用 qPrintable() 函数输出对象的信息qInfoqWarnin…...

C++读写excel文件的的第三方库
一、比较流行的库 1. OpenXLSX 用于读取、写入、创建和修改 Microsoft Excel (.xlsx) 文件的 C 库。 2. xlnt xlnt 是一个现代 C 库,用于操作内存中的电子表格以及从 XLSX 文件读取/写入它们,如ECMA 376 第 4 版中所述。xlnt 1.0 版的首次公开发布是在 …...

【关于Linux中----多线程(一)】
文章目录认识线程创建线程线程优点和缺点创建一批线程终止线程线程的等待问题认识线程 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&a…...