定时器

定时器

定时器是什么

定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定好的代码.
定时器是一种实际开发中非常常用的组件.
比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.
比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自动删除).
类似于这样的场景就需要用到定时器.

标准库中的定时器

标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .
schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后执行 (单位为毫秒).

 public static void main(String[] args){Timer timer=new Timer();//给timer中注册的这个任务,不是在调用schedule的线程中执行的,而是通过Timer内部的线程来负责执行的timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("定时器开始执行");}},3000);//这段代码代表程序开始三秒之后开始打印出  定时器开始执行  这句话System.out.println("程序开始执行");}

结果
在这里插入图片描述
我们发现程序并没有结束,为什么呢?
是因为Timer内部有自己的线程,为了保证随时可以处理新安排的任务,这个线程会持续执行,并且这个线程还是一个前台线程

一个定时器中可以有多个任务的,定时器会根据这些任务设置的时间来合理的分配执行顺序

    public static void main(String[] args){Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("3");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("2");}},2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("1");}},1);System.out.println("程序开始执行");}

我们可以看到,虽然先给 3 分配了任务,但是任务 1 先执行了,是因为任务3的时间比任务1长

实现定时器

思路
在这里插入图片描述
优化
在这里插入图片描述

相关问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class MyTimerTask implements Comparable<MyTimerTask>
{//表示任务啥时候执行,这是一个毫秒级时间戳private long time;//表示任务具体是啥private Runnable runnable;public MyTimerTask(Runnable runnable,long delay){//delay是一个相对的时间差,例如3000这样的数值//构造time是要根据当前系统时间和delay进行构造time=System.currentTimeMillis()+delay;this.runnable=runnable;}public long getTime(){return time;}public Runnable getRunnable(){return runnable;}@Overridepublic int compareTo(MyTimerTask o){//认为时间小的优先级高,最终时间最小的元素就会放到队首return (int)(this.time-o.time);}
}
//定时器类的本体
class MyTimer
{//用来加锁的对象private Object locker=new Object();//使用优先级队列来保证上述的N个任务private PriorityQueue<MyTimerTask> queue=new PriorityQueue<>();//定时器的核心方法,就算把要执行的任务添加到队列中public void schedule(Runnable runnable,long delay){synchronized (locker){MyTimerTask task=new MyTimerTask(runnable,delay);//这个集合类不是线程安全的,即会在主线程中使用,又会在扫描线程中使用,这就触发了线程安全问题,两个线程针对同一个集合作用,因此要加锁queue.offer(task);//每次来新的任务,都唤醒一下之前的扫描线程,重新规划等待时间locker.notify();}}//MyTimer中还需要构造一个”扫描线程“,一方面去负责监控队首元素是否到点了,是否应该执行//另一方面当任务到点之后,就要调用这里的Runnable的run方法来完成任务public MyTimer(){Thread t=new Thread(()->{while(true){try{synchronized (locker){//扫描线程中几乎都会涉及到queue,因此全加锁while(queue.isEmpty()){//如果当前队列为空,此时就不应该去取这里的元素//continue;//此处使用wait等待更合适,如果使用continue,就会使这个线程while循环运行的飞快//也会陷入一个高频占用cpu的状态(忙等)locker.wait();}MyTimerTask task=queue.peek();long curTime=System.currentTimeMillis();if(curTime>=task.getTime()){//假设当前时间是12:01,任务时间是12:00,此时就意味着要执行这个任务了//执行任务之后把这个任务从队列中去除掉queue.poll();//执行当前这里的任务的内容task.getRunnable().run();}else{//如果任务时间没到//让当前扫描线程休眠一下,按照时间差来休眠//Thread.sleep(task.getTime()-curTime);locker.wait(task.getTime()-curTime);}}}catch (InterruptedException e){e.printStackTrace();}}});t.start();}
}
//写一个定时器
public class Demo22
{public static void main(String[] args){MyTimer timer=new MyTimer();timer.schedule(new Runnable() {@Overridepublic void run(){System.out.println("任务3");}},3000);timer.schedule(new Runnable() {@Overridepublic void run(){System.out.println("任务2");}},2000);timer.schedule(new Runnable() {@Overridepublic void run(){System.out.println("任务1");}},1000);System.out.println("任务开始执行:");//}
}

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

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

相关文章

MAUI+Blazor:windows 打包踩坑

文章目录 前言MSIX安装文件如何发布选择Windows平台旁加载自定义签名版本号安装 总结 前言 最近打算研究一下MAUIBlazor&#xff0c;争取在今年年底之前彻底搞懂MAUIBlazor的安装模式&#xff0c; MSIX安装文件 Windows 4种安装程序格式MSI&#xff0c;EXE、AppX和MSIX优缺点…

uni-app之app上传pdf类型文件

通过阅读官方文档发现&#xff0c;uni.chooseFile在app端不支持非媒体文件上传&#xff1b; 可以使用这个插件&#xff0c;验证过可以上传pdf&#xff1b;具体使用可以去看文档 插件地址 就是还是会出现相机&#xff0c;这个可能需要自己解决下 实现功能&#xff1a;上传只能上…

详解Linux文本三剑客

目录 一、grep 1.什么是grep? 2.如何使用&#xff1f; 3.正则 二、sed 1.认识sed? 2.如何使用&#xff1f; 三、awk&#xff08;重点&#xff09; 1.awk变量 1.1内置变量 1.2自定义变量 2.awk数组 四、经典实战案例 案例一&#xff1a;筛选IPv4地址 案例二&am…

Oracle 开发篇+Java通过DRCP访问Oracle数据库

标签&#xff1a;DRCP、Database Resident Connection Pooling、数据库驻留连接池释义&#xff1a;DRCP&#xff08;全称Database Resident Connection Pooling&#xff09;数据库驻留连接池&#xff08;Oracle自己的数据库连接池技术&#xff09; ★ Oracle开启并配置DRCP sq…

Win11 VS2022 配置CGAL-5.6

由于项目要用到几何库CGAL&#xff0c;因此做了配置。采用的是官方文档中的“Installing from the Source Archive”方式。 1. 下载安装CGAL &#xff08;1&#xff09;CGAL-5.6.zip下载地址&#xff1a;Releases CGAL/cgal GitHub 下载下图所示的两个文件。 &#xff08…

竞赛项目 深度学习实现语义分割算法系统 - 机器视觉

文章目录 1 前言2 概念介绍2.1 什么是图像语义分割 3 条件随机场的深度学习模型3\. 1 多尺度特征融合 4 语义分割开发过程4.1 建立4.2 下载CamVid数据集4.3 加载CamVid图像4.4 加载CamVid像素标签图像 5 PyTorch 实现语义分割5.1 数据集准备5.2 训练基准模型5.3 损失函数5.4 归…

图像变形之IDW和RBF(附源码)

IDW原理 IDW(Inverse distance weighted interpolation)图像变形算法根据给定的控制点对和控制点对的位移矢量(方向和距离)&#xff0c;计算控制点对周围像素的反距离加权权重影响&#xff0c;从而实现图像每一个像素点的位移&#xff0c; 假设输入控制点pi&#xff0c;其对应…

Vue中data变量使用的注意事项

因为在Vue中&#xff0c;data中的属性往往都是用于双向绑定&#xff0c;所以Vue会对其有劫持&#xff0c;所以我们在对data属性进行操作时&#xff0c;尽量不要对其直接操作&#xff0c;比如下面代码&#xff1a; export default {data() {return {list: []}},methods: {init(…

Unity游戏源码分享-儿童益智数学大脑训练游戏

Unity游戏源码分享-儿童益智数学大脑训练游戏 5秒内选择答案 项目下载地址&#xff1a;https://download.csdn.net/download/Highning0007/88198773

JavaFx异常: Not on FX application thread; currentThread = Timer-0

我的定时器任务中有两个控件&#xff1a; FXML TextArea Display; FXML Label Label_Display; 执行下方代码会抛出&#xff1a;Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread Timer-0 Timer_tas…

xcode打包导出ipa

转载&#xff1a;xcode打包导出ipa 目录 转载&#xff1a;xcode打包导出ipa 第一步&#xff1a;注册苹果开发者账号 第二步&#xff1a;下载APP Uploader 第三步&#xff1a;使用xcode打包导出ipa文件&#xff0c;供其他人内测 众所周知&#xff0c;在开发苹果应用时需要使…

操作系统 -- 进程间通信

一、概述 进程经常需要与其他进程通信。例如&#xff0c;在一个shell管道中&#xff0c;第一个进程的输出必须传送给第二个进程&#xff0c;这样沿着管道传递下去。因此在进程之间需要通信&#xff0c;而且最好使用一种结构良好的方式&#xff0c;不要使用中断。在下面几节中&…