当前位置: 首页 > news >正文

简单学习 -->定时器

定时器 (常见的组件)

定时器 作用:例如: (定时发邮件) , 像一个闹钟一样.

例如:客户端向服务器请求,如果服务器不响应就 , 等 , 等到最大时间过了,就不等.

这里的 等待的最长时间, 就是通过计时器来实现.

Timer (java中的计时器)

Timer , 在util包里

schedule() 方法

两个参数 , 一个描写了 时间到了 要做什么事情 , 一个 是 任务多少ms 时间 后执行 ;

  1. main主线程 调用 schedule () , 方法 , 把 任务 给 Timer 对象中 , Timer 对象 中有一个线程 "扫描线程" , 会扫描时间是否到了,一旦时间到了 ,就会执行刚才安排 的任务 .

  2. 因为Timer里也有一个线程 , 所以 执行刚才的代码 , 程序并没有停止 ; 因为主线程走完了,但是还有一个Timer的扫描线程

public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("时间到执行任务"); } }, 2000 ) ; System.out.println("计时器开始执行"); } 输出了 计时器开始执行 时间到执行任务
Timer里可以安排多个 任务 , 去执行 ;
public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("2000时间到执行任务"); } }, 2000 ) ; timer.schedule(new TimerTask() { @Override public void run() { System.out.println("3000时间到,执行任务"); } } , 3000); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("1000时间到,执行任务"); } } , 1000); System.out.println("计时器开始执行"); } 输出 计时器开始执行 1000时间到,执行任务 2000时间到执行任务 3000时间到,执行任务

实现一个简单的计时器

步骤:

1.有一个扫描线程 , 来看时间是否到了 , 要执行任务

如果时间到了 ,就执行任务, 如果时间没到 就不执行 ;

2.需要一个数据结构, 来存放 我们的任务

类似于阻塞队列 ,如果是空 ,就wait , 如果不空notify

3.还要有一个类 , 类方法 来描述一个 任务 (方法里要有 任务 内容 和 时间)

这个类里 放 任务属性 , 时间 , 作为 我们数据结构的参数,来使用;

实现 代码

import java.util.PriorityQueue; ​ // 一个类 , 类里有 任务 ,有时间 , 用来 描述一个任务(带任务,和时间) class MyTimerTask implements Comparable<MyTimerTask>{ // 用 runnable 是任务 private Runnable runnable; // long 类型的时间戳 private long time ; // delay 传入的 时间就是 一个 相对的时间 , 获取 现在的绝对时间 + delay 就是 任务执行的时间 public MyTimerTask(Runnable runnable, long delay) { this.runnable = runnable; this.time = System.currentTimeMillis() + delay; } // 实现comparable , 用时间做比较 @Override public int compareTo(MyTimerTask o) { return (int) (this.time - o.time); } ​ // 获取时间 public long getTime(){ return time; } // 获取 任务 public Runnable getRunnable(){ return runnable; } } ​ class MyTimer{ // 用优先级队列 来 , 存储 任务 ; private PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>(); ​ public void schedule(Runnable runnable , long delay){ // 定义锁 让线程安全 synchronized(locker){ priorityQueue.offer(new MyTimerTask(runnable, delay)); // 如果不队列不为空就 notify locker.notify(); } } // 定义一个锁 ,让 schedule 方法 ,和扫描线程 ,安全 private Object locker = new Object(); ​ //设置扫描线程 ,让扫描线程 去执行 run; public MyTimer(){ // 扫描线程 来 从 队列中取 元素 , Thread t1 = new Thread(()->{ // while 循环去取元素 while (true){ try{ // 加锁让线程安全 synchronized(locker){ // while 来判断 队列是否是空 , 空就wait while (priorityQueue.isEmpty()){ locker.wait(); } // 如果不为空 就 查看队列顶元素 MyTimerTask task = priorityQueue.peek(); // 查看时间到了没有 ,到时间就执行run方法 //获取现在的时间 long curTime = System.currentTimeMillis(); if(curTime >= task.getTime()){ // 执行run task.getRunnable().run(); // 执行完后就 释放栈顶 priorityQueue.poll(); }else{ // 时间没有到就继续循环 ,等时间到了可以执行run } } }catch (InterruptedException e){ e.printStackTrace(); } } }); // 启动 扫描线程 t1.start(); } ​ } public class Test2 { public static void main(String[] args) { MyTimer myTimer = new MyTimer(); myTimer.schedule(new Runnable() { @Override public void run() { System.out.println("1000ms的任务"); } }, 1000); myTimer.schedule(new Runnable() { @Override public void run() { System.out.println("2000ms的任务"); } }, 2000); myTimer.schedule(new Runnable() { @Override public void run() { System.out.println("3000ms的任务"); } }, 3000); System.out.println("计时器开始计时"); } } ​

问题

时间过久问题

如果 我有一个任务 是 8点执行 , 但是现在才 7点 ; while 循环里就一直 的在运转(不断在消耗);

因为 while 循环里 , 一直在循环 , 时间没有到 ,导致while 一直在快速运转 ; 一直做没有意义的事情

在else 加一个 wait (带时间) , 让 线程wait() , 这样就不消耗资源了

使用 wait, 不使用 sleep , 是因为 wait , 可以被 notify 唤醒 , 在 添加一个 delay 时间小的任务 时 , 就可以唤醒, 然后 用这个小的时间来wait() ;

在有新任务时 ,就唤醒一下 , 更新一下最近的任务 是谁 ,更新最近任务的时间

使用PriorityQueue 不用 PriorityBlockingQueue就 是 , PriorityBlockingQueue 不能够处理 我们上面的 两个wait () ;

也可以给 添加任务的 delay 加些判断 , 例如 delay 不能< 0 , 或者 if() else() 判断里 curTime 的时间不能比 任务时间 小(时间都已经过了 , 还执行什么)

http://www.jsqmd.com/news/804506/

相关文章:

  • 【MySQL 数据库】内外连接
  • 生成式引擎优化(GEO):AI时代企业流量增长新范式,源头服务商赋能品牌长效增长# - 麒麟芯geo4008005528
  • 热门去水印软件实测对比 哪一款清理更彻底 - 爱上科技热点
  • 广州聚杰芯科交通流量调查系统,2026十大品牌优选,值得信赖的监测专家 - 品牌速递
  • 使用curl命令直接调试Taotoken大模型聊天接口的详细步骤
  • 哔咔漫画下载器完整指南:快速构建个人离线漫画库
  • Pandas高效数据处理:筛选特定行实例解析
  • 编程应届生面试,技术面必问的20个核心知识点,全在这里
  • GoDaddy域名批量管理利器gd-plug:命令行自动化实战指南
  • 手机上如何去除视频水印?多种方法一次性教 - 爱上科技热点
  • 不止点灯:用ZCU102的MIG控制器和VIO IP实时调试DDR4读写状态
  • 企业AI智能体生产级落地:架构、技术栈与工程实践全解析
  • 微信里哪个小程序免费去水印?2026最新安全无套路推荐 - 爱上科技热点
  • Mac Mouse Fix:如何彻底改变macOS鼠标体验的5个关键技术
  • 构建AI长期记忆系统:突破上下文窗口限制的架构与实现
  • a16z 领投,前 Deepmind 研究员创立 Ethos:基于语音智能体的人才匹配平台;印度成为 Wispr Flow 第二大市场丨日报
  • 大模型 Agent 面试高频100题——基础篇
  • 编程统计企业水电物业日常开销数据,分析资源浪费时段,制定节能方案,降低公司固定运营成本。
  • 机器学习模型优化:从梯度下降到Adam,超越调参的本质理解
  • 使用Taotoken后API调用延迟与稳定性实际观测体验
  • 对话式AI编程助手JotBot:本地优先的代码生成与重构实践
  • 有没有完全免费的去水印工具?免费去水印工具无需付费 2026 实测推荐 - 爱上科技热点
  • MIUI 12 下 Google Play 登录“卡核对”?一个权限与重启的破局思路
  • 欧盟AI战略:从监管框架到技术主权的欧洲路径
  • 私域电商直播怎么做?500+品牌都在用的增长秘籍
  • 大模型长文本处理范式革命(Claude 2026推理引擎内核首次公开)
  • 如何打破语言壁垒:XUnity自动翻译器终极指南
  • 基于React与Tailwind CSS的轻量级ChatGPT Web界面部署与定制指南
  • 在 Taotoken 平台观测不同模型调用延迟与成功率的心得
  • 本地推荐:优质激光切管机厂家及选型要点全解析 - GrowthUME