当前位置: 首页 > 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.dtcms.com/a/341230.html

相关文章:

  • 无人机感知系统详解
  • Excel表格复制到word中格式错乱
  • 【Java】深入浅出Spring中的@Autowired:自动注入的奥秘
  • 机器翻译 (Machine Translation) 经典面试笔试50题(包括详细答案)
  • imx6ull-驱动开发篇29——Linux阻塞IO 实验
  • Java并发容器详解
  • 【LLIE专题】BEM:一对多映射,贝叶斯增强模型
  • Deepseek+python自动生成禅道测试用例
  • 将集合拆分成若干个batch,并将batch存于新的集合
  • WMS仓储管理系统如何解决仓库的呆滞库存
  • 鸿蒙安卓前端中加载丢帧:ArkWeb分析
  • 第5.7节:awk赋值运算
  • IPSEC安全基础
  • Qt 中最经典、最常用的多线程通信场景
  • TDengine IDMP 运维指南(数据导入导出)
  • WIN10/WIN11:无法下载所有必需的文件 0x80072EE2 0x20000(未解决)
  • C++ std::sort的应用总结
  • Unity 大量子弹和小怪碰撞检测优化
  • GSPO:Towards scalable reinforcement learning for language models
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型和EasyOCR实现汽车牌照动态检测和识别(C#代码,UI界面版)
  • 使用UUP dump制作windows preview镜像
  • 手机、汽车如何实现卫星直连
  • imx6ull-驱动开发篇31——Linux异步通知
  • 玩转QEMU硬件模拟器 - Raspberry Pi OS驱动开发
  • 【项目复盘】【四轴飞行器设计】驱动开发部分
  • Redis 安装教程
  • 【数据结构之二叉树】
  • 【openssl】openssl CA.pl 签发证书操作步骤
  • redis执行lua脚本的原子性和数据库原子性的区别
  • [激光原理与应用-315]:光学设计 - SolidWorks, 光机系统设计的神器,打通光学与机械设计的闭环