手搓一个定时器
目录
1.什么是定时器
2.计时器的使用
3.手搓定时器
3.1定义一个TimerTask类
3.2定义一个Timer类
3.3实现schedule方法
3.4实现Timer的构造方法
3.4.1随时随地查看优先级队列中是否有任务要执行
3.4.2获取队首任务,并判断是否到执行时间
3.4.3到达执行时间执行任务
4.整体的一个代码:

1.什么是定时器
在看警匪片时,经常会有匪徒在银行安装定时炸弹,而这里的定时炸弹就可以看成一个定时器,当设定的时间到时,炸弹就会爆炸,而我们这里的定时器是当时间到时,就会执行相应的任务
2.计时器的使用
在Java中,关于计时器的类时Timer
Timer类是java.util包提供的API。
Timer中最主要的方法是schedule方法,他是将我们的任务,和时间放进一个数组模拟的队列中,然后在指定时间执行指定的任务
代码示例:
import java.util.Timer;
import java.util.TimerTask;public class Main19 {public static void main(String[] args) {Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 3000");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 2000");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello 1000");}},1000);System.out.println("hello main");}
}
schedule的第一个参数类型是TimerTask,这个类他继承了Runnable类,然后第二个参数是,当前程序运行多少时间执行这个任务,单位是ms
3.手搓定时器
简单介绍完java中的Timer的使用,下面我们就来模拟实现一个定时器
整体的一个思路:
1.定义任务类(TimerTask):用来存储每一个任务的属性,如执行的时间,以及要执行的任务
2.定义一个Timer类(定时器):每一个任务执行的先后顺序,以及执行过程中的一些细节问题
3.1定义一个TimerTask类
class TimerTask{private Runnable task;private long time;public TimerTask(Runnable task, long time) {this.task = task;this.time = time;}
}
在这个类中成员属性分别为要执行的任务,以及任务执行的时间,还有一个构造方法
3.2定义一个Timer类
class Timer{private PriorityQueue<TimerTask>queue=new PriorityQueue<>();public void schedule(Runnable task,long time){}public Timer() {Thread t=new Thread(()->{});t.start(); }}
1.在这个类中有一个优先级队列,这个是用来给各个任务执行的先后顺序进行排序的
2.schedule是用来将我们要执行的任务添加到优先级队列当中的
3.Timer()这个构造方法,是我们在创建这个类时,他就开启了一个线程,这个线程是用来按时间执行我们队列中的任务的,如果线程中有任务他就在指定时间去执行,如果没有任务,他就阻塞等待
3.3实现schedule方法
锁对象:
Object lock=new Object();
schedule方法:
public void schedule(Runnable task,long delay){synchronized (lock){TimerTask timerTask=new TimerTask(task, System.currentTimeMillis()+delay);queue.offer(timerTask);}}
1.我们实例化一个TimerTask的对象,然后将schedule的参数作为任务,以及时间传递给TimerTask的构造方法作为参数(注意的是:这里构造方法接收的时间是任务执行的时间,而schedule参数的时间是任务距离调用schedule调用时相差的时间),所以构造方法参数的时间,我们要用当前时间加上延迟的时间(获取当前时间:System.currentTimeMillis());
2.得到TimerTask这个对象后,我们要将这个对象添加到优先级队列当中
3.在实例化Timer时,构造方法也会启动一个线程,所以我们这是一个多线程的程序,为了保证线程安全,我们给其加上一个锁
因为我们向优先级队列中添加的是我们自定义的类,他不知道该怎么对齐进行排序,所以我们要对TimerTask这个类定义一个比较规则
class TimerTask implements Comparable<TimerTask>{@Overridepublic int compareTo(TimerTask o) {return (int)(this.time-o.time);}
}
我们将TimerTask实现一个Comparable接口,并重写Comparaable接口里面的comparaeTo方法,又因为我们想让时间近的任务放在队首,所以我们的比较规则是为了实现一个小根堆,如果this.time-o.time是一个整数就会将小的任务放在前面,然而我们的时间是long类型,我们需要将this.time-o.time的值强转为int类型
3.4实现Timer的构造方法
3.4.1随时随地查看优先级队列中是否有任务要执行
public Timer() {Thread t=new Thread(()->{while(true){try {synchronized (lock){while(queue.isEmpty()){lock.wait();}}} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}
1.第一个while循环是当一次任务执行完毕,再次查看队列中是否有要执行的任务
2.第二个while循环是查看队列中是否有任务,如果没有任务,我们就阻塞等待,直到schedule被调用时,我们这里的wait被唤醒,然后进行接下来的操作
3.wait一般搭配synchronized来使用保证线程安全
为了在队列为空时,向队列中添加任务后,需要将wait唤醒,所以在schedule方法中要加上notify
public void schedule(Runnable task,long delay){synchronized (lock){TimerTask timerTask=new TimerTask(task, System.currentTimeMillis()+delay);queue.offer(timerTask);lock.notify();}}
3.4.2获取队首任务,并判断是否到执行时间
TimerTask task=queue.peek();if(System.currentTimeMillis()<task.getTime()){lock.wait(task.getTime()-System.currentTimeMillis());}
1.获取队首任务,使用peek,而不使用poll
2.如果未到达执行时间,我们就阻塞等待任务执行时间和当前时间之间的时差
3.如果在这个阻塞等待的时间段内,使用schedule向队列中添加了一个比当前任务更早的任务,schedule中的notify会将我们这里的带时间的wait唤醒,然后重新获取队列中的队首任务
3.4.3到达执行时间执行任务
if(System.currentTimeMillis()<task.getTime()){lock.wait(task.getTime()-System.currentTimeMillis());}else {task.run();queue.poll();}
1.这里使用else,也就是当当前系统时间大于等于任务执行的时间,执行任务
2.如果不使用else,当在等待过程中,新插入一条任务,那么就会解除阻塞,执行run和poll,从而导致程序出错
task.run方法需要我们在TimerTask类中进行实现
public void run(){task.run();}
4.整体的一个代码:
package Demo4;import java.util.PriorityQueue;class TimerTask implements Comparable<TimerTask>{private Runnable task;private long time;public TimerTask(Runnable task, long time) {this.task = task;this.time = time;}public void run(){task.run();}public long getTime() {return time;}@Overridepublic int compareTo(TimerTask o) {return (int)(this.time-o.time);}
}class Timer{private PriorityQueue<TimerTask>queue=new PriorityQueue<>();Object lock=new Object();public void schedule(Runnable task,long delay){synchronized (lock){TimerTask timerTask=new TimerTask(task, System.currentTimeMillis()+delay);queue.offer(timerTask);lock.notify();}}public Timer() {Thread t=new Thread(()->{while(true){try {synchronized (lock){while(queue.isEmpty()){lock.wait();}TimerTask task=queue.peek();if(System.currentTimeMillis()<task.getTime()){lock.wait(task.getTime()-System.currentTimeMillis());}else {
task.run();
queue.poll();}}} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}public class Main10 {public static void main(String[] args) {Timer timer=new Timer();timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 3000");}},3000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 2000");}},2000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 1000");}},1000);}
}
完结:
相关文章:
手搓一个定时器
目录 1.什么是定时器 2.计时器的使用 3.手搓定时器 3.1定义一个TimerTask类 3.2定义一个Timer类 3.3实现schedule方法 3.4实现Timer的构造方法 3.4.1随时随地查看优先级队列中是否有任务要执行 3.4.2获取队首任务,并判断是否到执行时间 3.4.3到达执行时间…...
AI提示词工程优化Prompt-GPT使用手册(科普一键收藏史上最强攻略)
Prompt(提示),最初是 NLP 研究者为下游任务设计出来的一种任务专属的输入形式或模板。在 ChatGPT 引发大语言模型新时代之后,Prompt 指与大模型交互输入的代称。 随着大模型的进展,Prompt Engineering是一个持久的探索过程。 目录 什么是提示…...
【数据结构】快速排序(三种实现方式)
目录 一、基本思想 二、动图演示(hoare版) 三、思路分析(图文) 四、代码实现(hoare版) 五、易错提醒 六、相遇场景分析 6.1 ❥ 相遇位置一定比key要小的原因 6.2 ❥ 右边为key,左边先走 …...
利用前向勾子获取神经网络中间层的输出并将其进行保存(示例详解)
代码示例: # 激活字典,用于保存每次的中间特征 activation {}# 将 forward_hook 函数定义在 upsample_v2 外部 def forward_hook(name):def hook(module, input, output):activation[name] output.detach()return hookdef upsample_v2(in_channels, o…...
CTF-RE 从0到N: S盒
S盒(Substitution Box) 是密码学中的一种替换表,用于对输入数据进行非线性变换,以增加加密过程的复杂性。它主要用于对称加密算法中(例如AES、DES),作为加密轮次的一部分,对输入字节…...
MT-Pref数据集:包含18种语言的18k实例,涵盖多个领域。实验表明它能有效提升Tower模型在WMT23和FLORES基准测试中的翻译质量。
2024-10-10,由电信研究所、里斯本大学等联合创建MT-Pref数据集,它包含18种语言方向的18k实例,覆盖了2022年后的多个领域文本。通过在WMT23和FLORES基准测试上的实验,我们展示了使用MT-Pref数据集对Tower模型进行对齐可以显著提高翻…...
【C++ 真题】B2099 矩阵交换行
矩阵交换行 题目描述 给定一个 5 5 5 \times 5 55 的矩阵(数学上,一个 r c r \times c rc 的矩阵是一个由 r r r 行 c c c 列元素排列成的矩形阵列),将第 n n n 行和第 m m m 行交换,输出交换后的结果。 输入格式 输入共 6 6 6 …...
AAPL: Adding Attributes to Prompt Learning for Vision-Language Models
文章汇总 当前的问题 1.元标记未能捕获分类的关键语义特征 如下图(a)所示, π \pi π在类聚类方面没有显示出很大的差异,这表明元标记 π \pi π未能捕获分类的关键语义特征。我们进行简单的数据增强后,如图(b)所示,效果也是如…...
MySQLDBA修炼之道-开发篇(一)
三、开发基础 1. 数据模型 1.1 关系数据模型介绍 关于NULL 如果某个字段的值是未知的或未定义的,数据库会提供一个特殊的值NULL来表示。NULL值很特殊,在关系数据库中应该小心处理。例如查询语句“select*from employee where 绩效得分<85 or>绩…...
Spring MVC 知识点全解析
Spring MVC 知识点全解析 Spring MVC 是一个基于 Java 的请求驱动的 Web 框架,属于 Spring 框架的一部分,广泛用于构建企业级 Web 应用程序。本文将详细阐述 Spring MVC 的核心知识点,包括其工作原理、关键组件、配置、请求处理、数据绑定、…...
python 基于FastAPI实现一个简易的在线用户统计 服务
简易在线用户统计服务 概述 这是一个基于Python的FastAPI框架实现的服务,用于统计客户端的心跳信息,并据此维护在线用户列表以及记录活跃用户数。 功能特性 心跳接收:接受来自客户端的心跳包,以更新客户端的状态。在线用户统计…...
glibc中xdr的一个bug
本人在64位linux服务器上(centos7),发现xdr_u_long这个函数有个bug,就是数字的范围如果超过unsigned int的最大值(4294967295)时,xdr_u_long失败。 这个场景主要用在unix时间戳上面,比如一款软件,设置有效期为100年。…...
Android Framework定制sim卡插入解锁pin码的界面
文章目录 手机设置SIM卡pin码一、安卓手机二、苹果手机 Android Framework中SIM卡pin码代码定位pin码提示文本位置定位pin码java代码位置 定制pin码framework窗口数字按钮 手机设置SIM卡pin码 设置 SIM 卡 PIN 码可以提高手机的安全性,防止他人在未经授权的情况下使…...
cc2530 Basic RF 讲解 和点灯讲解(1_1)
1. Basic RF 概述 Basic RF 是 TI 提供的一套简化版的无线通信协议栈,旨在帮助开发者快速搭建无线通信系统。它基于 IEEE 802.15.4 标准的数据包收发,但只用于演示无线设备数据传输的基本方法,不包含完整功能的协议。Basic RF 的功能限制包括…...
Android H5页面性能分析策略
文章目录 引言一、拦截资源加载请求以优化性能二、通过JavaScript代码监控资源下载速度三、使用vConsole进行前端性能调试四、使用Chrome DevTools调试Android端五、通过抓包分析优化网络性能六、总结 引言 在移动应用开发中,H5页面的性能直接影响到用户体验。本文…...
【前端面试】Typescript
Typescript面试题目回答 Typescript有哪些常用类型? Typescript的常用类型包括: 基本类型:boolean(布尔类型)、number(数字类型)、string(字符串类型)。特殊类型:nul…...
程序语言的内存管理:垃圾回收GC(Java)、手动管理(C语言)与所有权机制(Rust)(手动内存管理、手动管理内存)
文章目录 程序语言的内存管理:垃圾回收、手动管理与所有权机制引言一、垃圾回收机制(GC)(Java)1. 什么是垃圾回收机制2. 垃圾回收的工作原理3. 优点与缺点4. 示例代码 二、手动管理内存的分配和释放(C语言&…...
研究生论文学习记录
文献检索 检索论文的网站 知网:找论文,寻找创新点paperswithcode :这个网站可以直接找到源代码 直接再谷歌学术搜索 格式:”期刊名称“ 关键词 在谷歌学术搜索特定期刊的关键词相关论文,可以使用以下几种方法&#…...
毕业设计选题:基于Django+Vue的图书馆管理系统
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 系统首页 图书馆界面 图书信息界面 个人中心界面 后台登录界面 管理员功能界面 用户…...
#网络安全#NGSOC与传统SOC的区别
NGSOC是Next Generation Security Operation Center(下一代安全运营中心)的缩写。 NGSOC安全运营服务基于态势感知与安全运营平台来开展监测分析等一系列的服务工作,旨在通过专业、高效的运营服务工作,帮助用户尽可能发挥NGSOC作…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...
OCC笔记:TDF_Label中有多个相同类型属性
注:OCCT版本:7.9.1 TDF_Label中有多个相同类型的属性的方案 OCAF imposes the restriction that only one attribute type may be allocated to one label. It is necessary to take into account the design of the application data tree. For exampl…...
