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

【JavaEE】多线程 -- 定时器

目录

  • 定时器是什么
  • 标准库中的定时器
  • 模拟实现定时器
  • 为什么不用阻塞队列中的优先级队列

定时器是什么

  • 定时器也是软件开发中的⼀个重要组件. 类似于⼀个 “闹钟”. 达到⼀个设定的时间之后, 就执⾏某个指定任务
  • ⽐如⽹络通信中, 如果对⽅ 500ms 内没有返回数据, 则断开连接尝试重连

标准库中的定时器

  • 标准库里面提供了一个Timer类, Timer类的核心方法是schedule(安排的意思)
  • schedule包含了个参数, 第一个参数是要执行的任务, 第二个参数是多久后执行(对于现在时间, 单位我为毫秒)
  • 第一个参数要重写TimerTask任务接口的run方法执行任务
  • 定时器里面内置了线程来执行这些任务
public class demo34 {public static void main(String[] args) throws InterruptedException {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");Thread.sleep(4000);timer.cancel();}
}
  • 这里用cancel来结束主线程, 因为我们定时器默认创建的是一个前台线程(也就是非守护线程). 前台线程不结束完, 进程也就不会结束

模拟实现定时器

class MyTimerTask implements Comparable<MyTimerTask>{private Runnable runnable;  //要执行的任务private long time; //任务在什么时候被执行, 以ms为单位public MyTimerTask(Runnable runnable, long delay){this.runnable = runnable;this.time = delay;}//获取到任务在什么时候被执行public long getTime(){return time;}public void run(){runnable.run(); //执行任务}@Overridepublic int compareTo(MyTimerTask o) {return (int)(this.time - o.time);}
}
class MyTimer{  //定时器类private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>(); //以执行时间最早的任务在第一个被执行private Object locker = new Object();public MyTimer(){//创建线程执行任务Thread t = new Thread(() -> {try {while (true) {synchronized (locker) { //这里任务队列, 取任务(写操作) MyTimerTask task = queue.peek(); //取出队首任务while (task == null) {locker.wait(); //如果队列为空, 那么让线程进入等待, 不去一直争抢锁, 忙等task = queue.peek();//唤醒后说明有任务了, 但是由于notify是随机唤醒, 有可能其他线程把任务先拿到, 所以这里获取到了重新while判断队列是否为空}//判断时间是否到达long curTime = System.currentTimeMillis();if(curTime >= task.getTime()){//时间到了task.run();queue.poll(); //执行完毕, 任务移除}else{//时间没到locker.wait(task.getTime() - curTime); //等到指定时间执行}}}}catch (InterruptedException e) {e.printStackTrace();}});t.start();}public void schedule(Runnable runnable, long delay){synchronized (locker){  //这里队任务队列添加任务(写操作)MyTimerTask myTimerTask = new MyTimerTask(runnable, delay);queue.add(myTimerTask);locker.notify(); //添加任务后唤醒线程, 告诉任务队列不为空}}
}

在这里插入图片描述

  • 测试
public class demo35 {public static void main(String[] args) {MyTimer timer = new MyTimer();timer.schedule(() -> {System.out.println("hello 3000");}, 3000);timer.schedule(() -> {System.out.println("hello 2000");}, 2000);timer.schedule(() -> {System.out.println("hello 1000");}, 1000);}
}

为什么不用阻塞队列中的优先级队列

  • 阻塞队列内置了锁, 这个时候我们自己也加了一把锁. 如果形成死锁条件(请求和保持)或者循环等待就成死锁了. 所以我们没必要冲冒这个风险
    在这里插入图片描述
http://www.lryc.cn/news/626593.html

相关文章:

  • GO环境变量中GO111MODULE到底是干啥的?
  • 心路历程-了解网络相关知识
  • 【论文阅读】Multi-metrics adaptively identifies backdoors in Federated Learning
  • Azure 使用记录
  • mapbox高阶,结合threejs(threebox)添加建筑glb模型,添加阴影效果,设置阴影颜色和透明度
  • 通过try-catch判断数据库唯一键字段是否重复
  • linux的内核符号表
  • 【表的操作】
  • 深入理解 Linux 多线程
  • mysql-8.0.37-linux-glibc2.12-x86_64安装
  • 可实现三重空间感知:Ai2 开源具身机器人 AI 模型 MolmoAct
  • 从防抖节流到链表树:编程世界中的抽象优化艺术
  • 23种设计模式——模板方法模式(Template Method Pattern)详解
  • 在一台没联网的机器上,用ollama加载qwen3,14b
  • 遥感机器学习入门实战教程|Sklearn 案例④ :多分类器对比(SVM / RF / kNN / Logistic...)
  • 使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
  • Spring Boot 配置
  • nvidia最新论文:小型语言模型是代理人工智能的未来
  • (5)软件包管理器 yum | Vim 编辑器 | Vim 文本批量化操作 | 配置 Vim
  • 5G-A赋能AR眼镜:毫米级虚实融合的未来已来
  • 开源 AR 眼镜怎么选?OpenGlass ,OSSG,cheApR 分析推荐
  • 给你的Unity编辑器添加实现类似 Odin 的 条件显示字段 (ShowIf/HideIf) 功能
  • 用好 Elasticsearch Ruby 传输层elastic-transport
  • 二维码跳转支付宝、微信小程序二码合一(直接关联、中间页识别跳转)方案
  • python-使用鼠标对图片进行涂抹自定义绘图
  • 自己微调的大模型如何用ollama运行
  • Android 开发问题:android:marginTop=“20px“ 属性不生效
  • 数字化图书管理系统设计实践(java)
  • Redis 复制功能是如何工作的
  • Linux I/O 多路复用实战:Select/Poll 编程指南