多线程(JavaEE初阶系列5)
目录
前言:
1.什么是定时器
2.标准库中的定时器及使用
3.实现定时器
结束语:
前言:
在上一节中小编给大家介绍了多线程中的两个设计模式,单例模式和阻塞式队列模式,在单例模式中又有两种实现方式一种是懒汉模式,一种是饿汉模式,在这两种模式中我们推荐大家使用的是懒汉模式,虽然饿汉模式是天然的线程安全的,但是与饿汉模式相比起来效率没有懒汉模式的高。在阻塞式队列中给大家重点提到了生产者和消费者模型,这个是我们以后会经常用到的一种模式,当时小编为了大家好理解给大家举了两个例子一个是包饺子,一个就是三峡大坝的削峰填谷,希望大家重点理解这两个例子。这节中小编将给大家讲解一下多线程中的定时器,讲解一下什么是定时器,定时器的使用以及手动实现一个定时器。
1.什么是定时器
定时器也是软件开发中的一个重要的组件,类似于一个“闹钟”,达到一个设定的时间之后,就执行某个指定好的代码。
比如:网络通信中,如果对方500ms内没有返回数据,则断开连接尝试重连,比如一个Map,希望里面的某个key在3s之后过期(自动删除),类似于这样的场景就需要用到定时器。
2.标准库中的定时器及使用
在标准库中提供了一个类:Timer类。
Timer timer = new Timer( );
Timer类的核心方法为schedule。
- schedule包含了两个参数,第一个参数指定即将要执行的任务代码,第二个参数指定多长时间之后执行(单位为毫秒)。
timer.schedule( new TimerTack( ) {
@Override
public void run() {
System.out.println("hello");
}
} , 3000 );
下面我们就在idea中来给大家具体演示一下:
代码展示:
package Time;import java.util.Timer;
import java.util.TimerTask;public class ThreadDemo1 {public static void main(String[] args) {//创建一个定时器Timer timer = new Timer();//让hello4、hello3、hello2、hello1在线程启动之后分别在4s、3s、2s、1s之后执行。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);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello1");}},1000);System.out.println("hello0");}
}
结果展示:

3.实现定时器
要想实现一个定时器我们就需要先来了解一下定时器的构成。
定时器的构成:
- 是一个带优先级的阻塞队列。
- 队列中的每一个元素是一个Task对象。
- Task中带有一个时间属性,队首元素就是即将要执行的元素。
- 同时有一个worker线程一直扫描队首元素,看队首元素是否需要执行。
这里给大家解释一下为啥要带优先级呢?
因为阻塞式队列中的任务都有各自执行时刻(delay),最先执行的任务一定是delay最小的,使用优先级的队列就可以高效的把这个delay最小的任务找出来了。所以这里的核心数据结构是“堆”!!!之前学习数据结构中的PriorityQueue就是一个带优先级的阻塞式队列。
注:具体的操作步骤请详细看代码内的注释!!!
代码展示:
package Time;import java.util.PriorityQueue;
class MyTask implements Comparable<MyTask>{public Runnable runnable;//为了方便后续的判定,使用绝对的时间戳public long time;public MyTask(Runnable runnable, long delay) {this.runnable = runnable;//取当前时刻的时间戳 + delay,作为该任务实际执行的时间戳。this.time = System.currentTimeMillis() + delay;}//指定一下在后续的优先级队列中我们是要按照时间来进行比较大小@Overridepublic int compareTo(MyTask o) {//这样的写法意味着每次取出的是时间最小的元素return (int) (this.time - o.time);}
}
//自己实现一个类似于Timer类的MyTimer
class MyTimer{//这个结构要求带有优先级的阻塞队列,核心数据结构就是“堆”。//PriorityQueue<> ———— <>里面的元素需要我们手动的封装一下,创建一个MyTask类,表示两方面的信息。1.执行的任务是啥。2.任务啥时候执行。private PriorityQueue<MyTask> queue = new PriorityQueue<>();//创建一个锁对象private Object locker = new Object();//此处的delay是一个形如3000这样的数字(指多长时间后执行该任务)public void schedule(Runnable runnable, long delay) {//根据参数,构造MyTask,插入队列即可。synchronized (locker) {synchronized (locker) {MyTask myTask = new MyTask(runnable, delay);queue.offer(myTask);locker.notify();}}}//在这里构造线程,负责执行具体的任务public MyTimer() {Thread t = new Thread(() -> {while (true) {try {synchronized (locker) {//阻塞队列,只有阻塞的入队列和阻塞的出队列,没有阻塞的查看队首元素。while (queue.isEmpty()) {locker.wait();}MyTask myTask = queue.peek();long curTime = System.currentTimeMillis();if (curTime >= myTask.time) {//时间到了,可以执行任务了queue.poll();myTask.runnable.run();} else {//时间还没到locker.wait(myTask.time - curTime);}}} catch (InterruptedException e) {e.printStackTrace();}}});//启动线程t.start();}
}
public class ThreadDemo2 {public static void main(String[] args) {//创建一个定时器对象MyTimer myTimer = new MyTimer();//模仿之前的使用方式使用myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello4");}}, 4000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello3");}}, 3000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello2");}}, 2000);myTimer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello1");}}, 1000);System.out.println("hello0");}
}
结果展示:

可以看到上述代码的执行结果与标准库中定时器的效果一样。
结束语:
这节中小编带着大家一起了解了Java标准库中定时器的使用方式,并给大家实现了一下定时器。希望这节对大家学习JavaEE有一定的帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)
相关文章:
多线程(JavaEE初阶系列5)
目录 前言: 1.什么是定时器 2.标准库中的定时器及使用 3.实现定时器 结束语: 前言: 在上一节中小编给大家介绍了多线程中的两个设计模式,单例模式和阻塞式队列模式,在单例模式中又有两种实现方式一种是懒汉模式&a…...
Minimum Snap闭式求解相关公式推导
文章目录 1 M i n i m u m Minimum Minimum S n a p Snap Snap闭式求解的推导1.1 二次规划等式约束构建1.2 求 d d d1.3 转成无约束优化问题 1 M i n i m u m Minimum Minimum S n a p Snap Snap闭式求解的推导 可以看看我的这几篇Blog1,Blog2,Blog…...
Spring源码(五)— 解析XML配置文件(一) bean标签解析流程
前面几章的内容已经介绍了BeanFactory创建前的准备工作,以及加载XML配置文件前的准备的步骤。本章会着重介绍解析XML的步骤。 registerBeanDefinitions 前几个方法不做过多的赘述,着重看registerBeanDefinitions方法中解析XML的步骤。 public int regi…...
隐私政策声明
http://lxfamn.cn/tools 我们注重对您个人隐私的保护。有时候我们需要某些信息才能为您提供您请求的服务,本隐私声明解释了这些情况下的数据收集和使用情况。本隐私声明适用于本网站的所有相关服务。如果您访问本网站、使用本网站的任何服务,那么您便接受…...
Flutter 最佳实践和编码准则
Flutter 最佳实践和编码准则 视频 前言 最佳实践是一套既定的准则,可以提高代码质量、可读性和可靠性。它们确保遵循行业标准,鼓励一致性,并促进开发人员之间的合作。通过遵循最佳实践,代码变得更容易理解、修改和调试ÿ…...
LangChain Agents深入剖析及源码解密上(一)
LangChain Agents深入剖析及源码解密上(一) LangChain Agents深入剖析及源码解密上 Agent工作原理详解 本节会结合AutoGPT的案例,讲解LangChain代理(Agent)为核心的内容。我们前面已经谈了代理本身的很多内容,也看了绝大部分的源代码,例如:ReAct的源代码,还有mrkl的源代…...
css定义超级链接a标签里面的title的样式
效果: 代码: 总结:此css 使用于任何元素,不仅仅是a标签!...
hcip——路由策略
要求: 基础配置 AR1 [R1]int g 0/0/0 [R1-GigabitEthernet0/0/0]ip add 12.0.0.1 24[R1-GigabitEthernet0/0/0]int g 0/0/1 [R1-GigabitEthernet0/0/1]ip add 14.0.0.1 24[R1]int loop0 [R1-LoopBack0]ip add 1.1.1.1 24[R1]rip 1 [R1-rip-1]vers 2 [R1-rip-1]net…...
ReID网络:MGN网络(1) - 概述
Start MGN 1. 序言 现代基于感知的信息中,视觉信息占了80~85%。基于视觉信息的处理和分析被应用到诸如安防、电力、汽车等领域。 以安防市场为例,早在2017年,行业咨询公司IHS Market,我国在公共和私人领域安装有摄像头约1.76亿…...
C++数据结构笔记(10)递归实现二叉树的三序遍历
对于三种遍历方式来说,均为先左后右!区别在于根结点的位置顺序 先序遍历:根——左——右 中序遍历:左——根——右 后序遍历:左——右——根 (所谓先中后的顺序,是指根结点D先于子树还是后于…...
hMailServer-5.3.3-B1879.exe
hMailServer-5.3.3-B1879.exe...
后端校验JSR303
目录 一、导入依赖 二、实现步骤 三、分组校验 四、自定义校验 一、导入依赖 <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version></dependency> 二…...
vmware磁盘组使用率100%处理
今天在外办事时,有客户发过来一个截图,问vmware 磁盘组空间使用率100%咋办?如下图: 直接回复: 1、首先删除iso文件等 2、若不存在ISO文件等,找个最不重要的虚拟机直接删除,删除后稍等就会释放…...
Redis实战(3)——缓存模型与缓存更新策略
1 什么是缓存? 缓存就是数据交换的缓冲区, 是存贮数据的临时区,一般读写性能较高 \textcolor{red}{是存贮数据的临时区,一般读写性能较高} 是存贮数据的临时区,一般读写性能较高。缓存可在多个场景下使用 以一次 w e b 请求为例…...
python与深度学习(十):CNN和cifar10二
目录 1. 说明2. cifar10的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测试。首…...
剑指offer12 矩阵中的路径 13 机器人的运动范围 34.二叉树中和为某一值得路径
class Solution { public:bool exist(vector<vector<char>>& board, string word) {int rowboard.size(),colboard[0].size();int index0,i0,j0;if(word.size()>row*col) return 0;//vector<vector<int>> visit[row][col];//标记当前位置有没有…...
Pushgateway+Prometheus监控Flink
思路方案 FlinkMtrics->pushgateway->prometheus->grafnana->altermanager 方案 : Flink任务先将数据推到pushgateway。然后pushgateway将值推送到prometheus,最后grafana展示prometheus中的值, 去这个 https://prometheus.io/download/ 下载最新的 Prometheu…...
OpenCV图像处理-视频分割静态背景-MOG/MOG2/GMG
视频分割背景 1.概念介绍2. 函数介绍MOG算法MOG2算法GMG算法 原视频获取链接 1.概念介绍 视频背景扣除原理:视频是一组连续的帧(一幅幅图组成),帧与帧之间关系密切(GOP/group of picture),在GOP中,背景几乎…...
nginx 反向代理浅谈
前言 通常情况下,客户端向Web服务器发送请求,Web服务器响应请求并返回数据。而在反向代理中,客户端的请求不直接发送到Web服务器,而是发送到反向代理服务器。反向代理服务器会将请求转发给真实的Web服务器,Web服务器响…...
【概率预测】对风力发电进行短期概率预测的分析研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
