多线程案例-定时器(附完整代码)

定时器是什么

定时器是软件开发中的一个重要组件.类似于一个"闹钟".达到一个设定的时间之后,就执行某个指定好的代码.

定时器是一种实际开发中非常常用的组件.

比如网络通信种,如果对方500ms内没有返回数据,则断开尝试重连.

比如一个Map,希望里面的某个key在3s之后过期(自动删除)

类似于这样的场景就需要用到定时器.

标准库中的定时器

标准库中提供了一个Timer类.Timer类的核心方法尾schedule.

schedule包含两个参数.第一个参数指定即将要执行的任务代码,第二个参数指定多长时间之后执行(单位为毫秒)

下面是代码示例:

public class TestTimer {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello timer");}}, 3000);System.out.println("hello main");}
}

运行代码,我们可以观察到一上来直接打印"hello main",然后三秒之后执行了"hello timer",为什么会出现这种情况呢?显然是每个Timer内置了一个线程.

 注:由于Timer内置了线程(前台线程),会阻止进程结束.这是因为timer不知道代码是否还会添加新的任务进来,就处于一种严阵以待的状态.

所以此处需要使用cancel()方法来主动结束,否则timer不知道其它什么地方还会添加任务.

public class TestTimer {public static void main(String[] args) throws InterruptedException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello timer");}}, 3000);System.out.println("hello main");Thread.sleep(4000);timer.cancel();}
}

这时就可以观察到进程结束成功了.

 

实现定时器

定时器的构成

一个带优先级队列(不要使用PriorityBlockingQueue,容易死锁!),而是使用PriorityQueue

 实现原理:

1.队列中每个元素是一个Task对象.

2.Task中带有时间属性,队首元素就是即将要执行的任务

3.同时有一个worker线程一直在扫描队首元素,看队首元素是否需要执行(先执行时间小的,后执行时间大的).

1.Timer类提供的核心接口为schedule,用于注册一个任务,并指定这个任务多长时间后执行.

public class MyTimer {public void schedule(Runnable runnable, long time) {//TODO}
}

2.Task类用于描述一个任务(作为Timer的内部类).里面包含着一个Runnable对象和一个time(毫秒时间戳)

这个对象需要放到优先级队列中,因此需要实现Comparable接口.

PriorityQueue, TreeMap, TreeSet都要求元素是"可比较大小的".需要Comparable,Comparator.

HashMap, HashSet则是要求元素是"可比较相等的","可hash的".因此需要实现

equals,hashCode方法

class MyTimerTask implements Comparable<MyTimerTask> {private Runnable runnable;//为了方便后续判定,使用了绝对的时间戳private long time;public MyTimerTask(Runnable runnable, long delay) {this.runnable = runnable;//取当前时刻的时间戳 + delay,作为该任务实际执行的时间戳this.time = System.currentTimeMillis() + delay;}@Overridepublic int compareTo(MyTimerTask o) {//这样的写法意味着每次去除的是时间最小的元素//到底是谁减谁,不要记,建议随便写个试一试return (int)(this.time - o.time);}
}

3.Timer实例中,通过PriorityQueue来组织若干个Task对象.

通过schedule往队列中插入一个个Task对象

class MyTimer {//核心结构private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();//创建一个锁对象private Object locker = new Object();public void schedule(Runnable runnable, long time) {//根据参数,构造MyTimerTask,插入队列即可synchronized(locker) {MyTimerTask myTimerTask = new MyTimerTask(runnable, delay);queue.offer(myTimerTask);locker.notify();}}
}

4.Timer类中存在一个worker线程,一直不停地扫描队首元素,看看是否能执行这个任务.

所谓能执行就是时间已经到达了. 

//在这里构建线程,负责执行具体的任务了
public MyTimer() {Thread t = new Thread(() -> {while(true) {try {synchronized(locker) {//阻塞队列,只有阻塞的入队列和阻塞的出队列,没有阻塞查看队首元素while(!queue.isEmpty()) {locker.wait();}MyTimerTask myTimerTask = queue.peek();long curTime = System.currentTimeMillis();if(curTime >= myTimerTask.getTime()) {//时间到了,可以执行任务了queue.poll();myTimerTask.run();} else {//时间还没到locker.wait(myTimerTask.time - curTime);}}} catch(InterruptException e) {e.printStackTrace();}}});t.start();
}

 下面附上完整代码以及解析:

import java.util.PriorityQueue;//通过这个类,来描述一个任务,这一整个任务,是要放到优先级队列中的
class MyTimerTask implements Comparable<MyTimerTask>{//在什么时间来执行这个任务//此处的time是一个ms级别的时间戳private long time;//实际任务要执行的代码private Runnable runnable;//delay期望是一个相对时间public MyTimerTask(Runnable runnable, long delay) {this.runnable = runnable;//计算一下要执行任务的绝对时间.(使用绝对时间,方便判定任务是否到达时间的)this.time = System.currentTimeMillis() + delay;}//实际执行代码的方法(一般在主函数中重写)public void run() {runnable.run();}//用于获得任务执行时间public long getTime() {return this.time;}//构建一个比较器(因为在优先级队列中是按时间对任务进行比较)@Overridepublic int compareTo(MyTimerTask o) {return (int)(this.time - o.time);}
}public class MyTimer{//构建一个线程private Thread t = null;//创建存放任务的主体--优先级队列private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();//创建一个锁对象private Object locker = new Object();//结束进程的方法public void cancel() {t.interrupt();}//构造方法:以用于创建线程public MyTimer() {t = new Thread(() -> {while(!Thread.interrupted()) {try {synchronized (locker) {while(queue.isEmpty()) {//当队列为空时,这个线程就一直处于阻塞等待的状态locker.wait();}//获得队列头部元素MyTimerTask task = queue.peek();//计算系统当前时间long curTime = System.currentTimeMillis();//判断是否应该执行if(curTime >= task.getTime()) {//执行任务queue.poll();task.run();} else {//等待到指定时间再执行任务locker.wait(task.getTime() - curTime);}}} catch (InterruptedException e) {break;}}});t.start();}//通过这个方法来执行实际的任务public void schedule(Runnable runnable, long delay) {synchronized (locker) {//先创建一个任务,后将任务放入队列MyTimerTask myTimerTask = new MyTimerTask(runnable, delay);queue.offer(myTimerTask);//唤醒因为队列中因为没有任务而阻塞等待的线程locker.notify();}}
}

 

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

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

相关文章

uniapp+vite+ts+express踩坑总结

1 关于引入express包报 import express from "express"; ^^^^^^ SyntaxError: Cannot use import statement outside a module的问题。 解决方案&#xff1a; 在package.json中添加type&#xff1a;“module”选项 2 Response is a type and must be imported …

c语言 词法分析器 《编译原理》课程设计

设计、编制并调试一个词法分析程序&#xff0c;加深对词法分析原理的理解。 针对表达各类词语的一组正规表达式&#xff0c;设计一个确定化的最简的有限自动机&#xff0c;对输入的符号串进行单词划分及词类识别。 要求词法分析器的输入是字符串&#xff0c;输出是源程序中各…

安装odoo17 Windows版时,PostgreSQL Database无法被勾选

安装odoo17 Windows版时&#xff0c;PostgreSQL Database无法被勾选。 出现的原因是&#xff0c;曾经安装过PostgreSQL Database&#xff1b;虽然可能已被卸载&#xff0c;但注册表内还有残余信息&#xff0c;导致odoo认为PostgreSQL Database仍存在于系统之中。 解决方案 删…

三勾商城新功能-电子面单发货

商家快递发货时可以选择在线下单,在线获取和打印电子面单。免去手写面单信息以及避免填写运单号填错,系统会自动填写对应发货商品的运单信息 快递100电子面单1、进入快递100&#xff0c;点击登录 2、登录成功后&#xff0c;点击“电子面单与云打印” 3、进入电子面单与云打印后…

AI全栈大模型工程师(二十七)如何部署自己 fine-tune 的模型

服务器价格计算器 火山引擎提供的这个价格计算器很方便&#xff0c;做个大概的云服务器 GPU 选型价格参考。其它服务厂商价格相差不是很多。 https://www.volcengine.com/pricing?productECS&tab2 高稳定和高可用地部署模型 序号模块名称描述1负载均衡将流入的请求分发到多…

基于Java SSM框架实现沙县小吃门店连锁点餐订餐系统项目【项目源码+论文说明】

基于java的SSM框架实现县小吃门店连锁点餐订餐系统演示 摘要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 沙县小吃点餐系统&#xff0c;主要的模块包括实现管理员&#xff1b;个人中心、用户管…

Linux 安装图形界面 “startx”

———————————————— 报错&#xff0c;如下&#xff1a; bash :startx command not found ———————————————— 解决方法&#xff1a; 1.先安装 — X Windows System&#xff0c;输入以下命令&#xff1a; yum groupinstall “X Window System”…

盘点2023年低代码平台TOP10

盘点2023年低代码平台TOP10 1 什么是低代码平台2 十大低代码平台2.1 IVX2.2 简道云2.3 伙伴云2.4 企名片one2.5 明道云2.6 轻流2.7 速融云2.8 轻舟——网易2.9 钉钉宜搭2.10 腾讯云-微搭 1 什么是低代码平台 低代码平台是一种开发软件的方法&#xff0c;它可以通过简单的拖放和…

【Anaconda】Ubuntu anaconda使用(新建环境、最小化安装Tensorflow)

Ubuntu anaconda使用&#xff08;新建环境、最小化安装Tensorflow&#xff09; 清华源地址&#xff1a; https://pypi.tuna.tsinghua.edu.cn/simplepip安装使用的时候&#xff0c; pip install xxx(库名) -i https://pypi.tuna.tsinghua.edu.cn/simple请先安装好anaconda&am…

Python 递归及目录遍历

递归调用&#xff1a;一个函数&#xff0c;调用了自身&#xff0c;称为递归调用 递归函数&#xff1a;一个会调用自身的函数 凡是循环能做的事&#xff0c;递归都能做。 目录 递归示例 普通方法实现 递归方式实现 计算分析&#xff1a; 递归遍历目录 引入os 遍历目录 执…

基于SSM的小儿肺炎知识管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

MobileNet网络

介绍 MobileNet 网络专注于移动端或者嵌入式设备中的轻量级CNN网络&#xff0c;相比传统卷积神经网络&#xff0c;在准确率小幅降低的前提下大大减少模型参数与运算量&#xff08;相比VGG16准确率减少了0.9%&#xff0c;但模型参数只有VGG的1/32&#xff09; 网络中的亮点&am…

利用知识付费小程序,我有才打造高效的知识传播渠道

在当今信息爆炸的时代&#xff0c;知识管理已经成为了每个人必须面对的问题。然而&#xff0c;市面上的知识付费平台大多数都是通用的&#xff0c;无法满足个性化需求。 因此&#xff0c;我有才提供了一款专属定制的适合个人的知识付费平台。核心产品能力如下&#xff1a; 一…

Java:TCP 通信方法(基本发送 + 接收)并 实现文件传输且反馈

TCP 通信编程 TCP:是一种可靠的网络协议&#xff0c;再通信两端都建立一个Socket对象。 通信之前要保证连接已经建立。 通过Socket产生IO流进行通信。 创建对象时&#xff0c;会连接服务器&#xff0c;连接不上&#xff0c;会报错。 所以&#xff0c;先运行服务端&#xff0c;再…

6大最佳目标进度管理软件盘点——团队/个人

在当今快节奏的生活和工作中&#xff0c;有效地管理目标和任务对于每个人来说都至关重要。在工作中&#xff0c;我们需要清晰地规划项目目标、安排任务和追踪进度&#xff1b;在生活中&#xff0c;我们也需要合理安排时间、记录重要事项以及追踪个人目标的实现进度。为了更好地…

【Maven技术专题】「知识盲区」教你如何使用深入分析Maven配置私服仓库的使用指南(基础篇)

Maven私服的使用实战 将内部构件部署到私服仓库什么是仓库和仓库组远程仓库的定义仓库定义基本结构仓库结构的属性介绍 部署部件到远程仓库远程仓库的认证用户名密码认证案例参考 私钥进行鉴权 镜像mirror镜像仓库的工作原理 将内部构件部署到私服仓库 如果想先学好什么如何将…

AMEYA360:海康存储PCIe4.0固态硬盘A4000介绍

海康存储即将发布PCIe4.0固态硬盘新品A4000&#xff0c;搭载全新定制主控及高品质3D NAND闪存颗粒&#xff0c;最大顺序读取速度达7100MB/s&#xff0c;提供五年质保服务。 2022年&#xff0c;海康存储开始在PCIe 4.0固态硬盘领域全面发力&#xff0c;推出C4000 ECO、C4000等多…

【OpenVINO】使用OpenVINO实现 RT-DETR 模型 INT8量化推理加速

使用OpenVINO实现 RT-DETR 模型 INT8量化推理加速 1. 使用 OpenVINO 实现 RT-DETR 模型 INT8量化1.1 神经网络压缩框架 &#xff08;NNCF&#xff09;1.2 准备校准数据集1.2.1 下载COCO验证数据集1.2.2 Validator包装器1.2.3 转换用于量化的数据集 1.3 定义模型精度校验方法1.4…

DBA轻松应对慢查询挑战,使用NineData这款工具就够了!

对于一个 DBA 来说&#xff0c;从公司数据库系统的稳定程度可以看出他的能力几何&#xff0c;一个优秀的 DBA 不仅要保证数据库的稳定运行&#xff0c;还需要有能力有效处理数据库的各种突发性能问题&#xff0c;而最常见的性能问题&#xff0c;就是慢查询。 我们公司规模比较…

docker-compose 单机容器编排

docker-compose 单机容器编排 dockerfile&#xff1a;先配置好文件&#xff0c;然后build&#xff0c;镜像------->容器 docker-conpose既可以基于dockerfile&#xff0c;也可以基于镜像&#xff0c;一件事拉起镜像和容器。 docker-compose 核心就是yml文件&#xff0c;可…