【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.…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
