Java定时器

article/2025/11/7 2:25:13

目录

一、认识定时器

1、什么是定时器

2、标准库的定时器

二、模拟实现定时器

1、描述定时器中的任务

2、管理多个任务

3、扫描线程

4、优化

5、最终代码


一、认识定时器

1、什么是定时器

        定时器是实际开发中常用的一个重要组件,类似于我们生活中的“闹钟”,达到设定的时间后,就执行某个指定的代码。

举个例子:

        在服务器开发中,客户端向服务器发送请求后,就需要等待服务器的响应,但是服务器不一定会立刻作出相应,而客户端也不能一直死等下去,那么就可以通过定时器来给客户端设置一个“等待时间” 。

2、标准库的定时器

标准库中的java.util.Timer包中提供了一个Timer类,即标准库的定时器:

我们可以创建一个Timer类的对象,通过该对象调用schedule方法来使用定时器:

public class Test {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("时间到,执行任务1");}},1000);}
}

schedule方法中有两个参数:

(1) 第一个参数是一个TimerTask对象,TimerTask是一个继承了Runnable接口的类,我们只需要new一个TimerTask对象,重写里面的run方法即可。

(2) 第二个参数表示指定的时间,单位是毫秒,即多长时间之后执行任务代码。

一个Timer对象可以安排多个任务:

可以看到,执行完三个任务之后,进程并没有结束,因为Timer类底层有一个阻塞队列~

二、模拟实现定时器

1、描述定时器中的任务

我们需要实现一个类,用来描述定时器中的任务,该任务包含两个信息:要执行的任务是什么,以及什么时候执行:

class MyTask{private Runnable runnable;//描述要执行的任务private long time;//什么时间执行,用时间戳来表示public MyTask(Runnable task,long delay){this.runnable = task;this.time = System.currentTimeMillis() + delay;}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}
}

2、管理多个任务

标准库中的定时器可以管理多个任务,我们在实现时也需要达到这样的效果~

如果同时有多个任务在等待执行时,那么肯定要首先执行等待时间最短的任务,所以我们考虑使用优先级队列,但优先级队列不是线程安全的,所以我们使用带有优先级功能的阻塞队列

public class MyTimer {private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();public void schedule(Runnable task,long delay) throws InterruptedException {MyTask myTask = new MyTask(task, delay);//把任务放入队列中queue.put(myTask);}
}

3、扫描线程

现在队列中已经可以存放任务了,但是没有人取这些任务~

所以我们还需要有一个扫描线程,来不停地对队列进行扫描,查看并执行队列中的任务~ 

这个扫描线程可以直接写在MyTimer的构造方法中,只要创建了对象,扫描线程就会开始工作~

    public MyTimer(){Thread t = new Thread(() -> {while (true){try {MyTask task = queue.take();//获取队首元素long curTime = System.currentTimeMillis();//获取当前时间//比较当前时间和队首元素的执行时间if(curTime >= task.getTime()){//时间到,执行任务task.getRunnable().run();}else {//时间没到,把元素再放回到队列中queue.put(task);}} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}

4、优化

(1) 实现Comparable接口,重写Comapare方法

当前的MyTask类还没有实现Comparable接口,所以当前类无法进行比较大小,从而在创建优先级阻塞队列时无法构建堆,此时运行代码就会抛出异常:

优化MyTask类:

class MyTask implements Comparable<MyTask>{private Runnable runnable;//描述要执行的任务private long time;//什么时间执行,用时间戳来表示public MyTask(Runnable task,long delay){this.runnable = task;this.time = System.currentTimeMillis() + delay;}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}@Overridepublic int compareTo(MyTask o) {return (int) (this.getTime()-o.getTime());}
}

(2) 优化扫描线程

        当前的扫描线程会频繁地取出/放入元素,但是如果离执行任务的时间还很远,那么这样频繁地操作,就会造成资源的浪费,并且这样频繁地取出/放入元素的操作也是毫无意义的~

举个栗子:

        假设现在是1点钟,我要在2点钟去上课,那么我只需要看一次时间,就可以知道还要过一个小时才会到上课时间,在上课之前我还可以做一些其他的事情;

        但是如果我每过一秒钟就看一下时间,每过一秒钟就看一下时间,这样做就会毫无意义,等待上课的过程中,我只能看时间,干不了别的事情。

    public MyTimer(){Thread t = new Thread(() -> {while (true){try {MyTask task = queue.take();//获取队首元素long curTime = System.currentTimeMillis();//获取当前时间//比较当前时间和队首元素的执行时间if(curTime >= task.getTime()){//时间到,执行任务task.getRunnable().run();}else {//时间没到,把元素再放回到队列中queue.put(task);synchronized (locker){locker.wait(task.getTime() - curTime);}}} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}public void schedule(Runnable task,long delay) throws InterruptedException {MyTask myTask = new MyTask(task, delay);//把任务放入队列中queue.put(myTask);synchronized (locker){//如果在线程等待期间,有新任务进入队列,则提前唤醒线程locker.notify();}}

(3) 最终优化 

当前代码中扫描线程会进行读操作,而schedule方法会进行写操作,那么在多线程环境下,同时进行这两种操作,必然会出现线程不安全的问题,所以我们需要把扫描线程中的读操作打包成一个原子操作:

    public MyTimer(){Thread t = new Thread(() -> {while (true){synchronized (locker) {try {MyTask task = queue.take();//获取队首元素long curTime = System.currentTimeMillis();//获取当前时间//比较当前时间和队首元素的执行时间if(curTime >= task.getTime()){//时间到,执行任务task.getRunnable().run();}else {//时间没到,把元素再放回到队列中queue.put(task);locker.wait(task.getTime() - curTime);}} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();}

5、最终代码

//描述任务的类
class MyTask implements Comparable<MyTask>{private Runnable runnable;//描述要执行的任务private long time;//什么时间执行,用时间戳来表示public MyTask(Runnable task,long delay){this.runnable = task;this.time = System.currentTimeMillis() + delay;}public Runnable getRunnable() {return runnable;}public long getTime() {return time;}@Overridepublic int compareTo(MyTask o) {return (int) (this.getTime()-o.getTime());}
}
//定时器
public class MyTimer {private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();Object locker = new Object();public MyTimer(){Thread t = new Thread(() -> {while (true){synchronized (locker) {try {MyTask task = queue.take();//获取队首元素long curTime = System.currentTimeMillis();//获取当前时间//比较当前时间和队首元素的执行时间if(curTime >= task.getTime()){//时间到,执行任务task.getRunnable().run();}else {//时间没到,把元素再放回到队列中queue.put(task);locker.wait(task.getTime() - curTime);}} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();}public void schedule(Runnable task,long delay) throws InterruptedException {MyTask myTask = new MyTask(task, delay);//把任务放入队列中queue.put(myTask);synchronized (locker){locker.notify();}}
}


http://chatgpt.dhexx.cn/article/cAnaCqKP.shtml

相关文章

matlab画图函数之plot【matlab图行绘制一】

plot函数 plot(x,y,’–gs’,‘LineWidth’,2,‘MarkerSize’,10,‘MarkerEdgeColor’,‘b’,‘MarkerFaceColor’,[0.5,0.5,0.5]) plot函数是最基本、最常用的绘图函数&#xff0c;用于绘制线性二维图。有多条曲线时&#xff0c;循环使用由坐标轴颜色顺序属性定义的颜色&…

Matlab画图线型、符号及颜色设置

1. matlab 中线条的主要属性 Color: 颜色LineStyle: 线型LineWidth: 线宽Marker: 标记点的形状MarkerFaceColor: 标记点填充颜色MarkerEdgeColor: 标记点边缘颜色MarkerSize: 标记点大小 2. 各种属性的名称 2.1 线型 -Solid line (default) – Dashed line : Dotted line …

matlab 画图基本

内容安排如下&#xff1a; 1、基本绘制&#xff08;图画大小、图形名称、图画背景、坐标轴名称、刻度范围、曲线颜色、坐标轴字体颜色等&#xff09;2、多条曲线&#xff08;plot hold on&#xff1b;plotyy&#xff1b;subplot&#xff1b;&#xff09;3、日期及时间轴绘图4、…

MATLAB画图详细教程

本文将详细介绍如何用matlab绘图并美化。 关于figure() 创建图窗窗口:figure() figure()的属性: Name:在标题栏显示的名称,接字符串,如Test Position:在电脑屏幕上的位置和大小,后接向量[left,bottom,width,height]也就是说指定了图窗的左下角位置,再向右+width、…

MATLAB画图总结

前言 在进行数据处理展示的时候&#xff0c;为了能直观体现实验的结果&#xff0c;需要进行绘图&#xff0c;让人们能直观的记住数据的走向特征&#xff0c;图像是结果的一种可视化展现&#xff0c;因此掌握一些绘图方法非常重要&#xff0c;使用MATLAB可以很简单的进行画图。下…

matlab 画图基本介绍

1.在命令窗口输入命令时&#xff0c;可以不必每输入一条命令就按enter键执行&#xff0c;可以在输入几行后一同运行。方法是&#xff1a;换行时&#xff0c;只要在按住<shift>键的同时按<enter>键即可&#xff0c;否则matlab就会执行上面输入的所有语句。 2.如何将…

matlab画图操作(修改坐标轴及字体,加粗,颜色修改,适合论文画图)

matlab常用画图操作 1.设置坐标轴2.设置figure大小3.matlab线条设置4.子图设置5.颜色查询6.colorbar设置7.线条透明度设置8.设置坐标轴刻度形式&#xff08;对数刻度&#xff09;9.图例设置10 文件保存11 消除白色边框12 添加子标题13 调换y轴递增顺序 1.设置坐标轴 %设置坐标…

使用matlab画图中图

又到一年论文季&#xff0c;没想到临近投稿的我居然会被图片的清晰度打败&#xff0c;需要子母图的时候&#xff0c;我直接使用powerpoint进行拼接&#xff0c;多次png另存为&#xff0c;图已经糊出了新高度&#xff0c;那种超级糊图在论文里应该是投不出去的吧。。。但是&…

matlab-画图对坐标的显示

前言 许多小朋友对于matlab画图函数再熟悉不过了&#xff0c;但是画图里面还有更细小的地方我们还得注意&#xff0c;对于坐标的显示也是我们在日常生活中常需要我们做的&#xff0c;下面我就将以一个例子1来说明在画图中显示坐标的两种形式。 下面的数据取样格式为 提示&a…

Matlab画图相关知识

目录 一、绘制不同种类的图像 1.1.画一般曲线图 1.2.绘制柱状图 二、matlab的图像处理 2.1将多张图同时绘制在一个Figure上面&#xff0c;采用subplot函数 2.2改变matlab图像坐标刻度增长幅度 2.3设置坐标轴刻度为任意值 2.4在一张Figure中用同一个x对应两个y作图 2.5关于…

MATLAB画图使用不同的线型、点及标记

转载自&#xff1a;MATLAB画图使用不同的线型、点及标记 (baidu.com) 一、 线型、连续标记 先从最普通的说起。在plot函数中指定线型。 tlinspace(0,5,20); x1 t; x2 2*t; x3 3*t; x4 4*t; plot(t,x1,b,t,x2,g-o,t,x3,r*,t,x4,c:d); 这是基础的比较简单的情况。不做…

MATLAB绘图

在MATLAB中绘制函数图形的步骤如下&#xff1a; 先定义变量 x&#xff0c;通过指定的变量 x 值的范围&#xff0c;该函数被绘制&#xff1b; 然后定义函数&#xff0c; y f(x)&#xff1b; 最后调用 plot 命令&#xff0c;如 plot(x, y)。 接下来我们通过例子绘制简单的函…

matlab画图入门教程

**matlab画图&#xff1a;**图像是数据结果的一种可视化表现&#xff0c;它能直观的体现你的数据结果&#xff0c;并且能体现你获得结果的准确性&#xff0c;在当前的大数据时代&#xff0c;在做数据分析的时候&#xff0c;将其可视化可以直观多维的展示数据&#xff0c;可以让…

MATLAB——画图(经典)

plot 二维线图全页折叠 #语法 plot(X,Y) plot(X,Y,LineSpec) plot(X1,Y1,…,Xn,Yn) plot(X1,Y1,LineSpec1,…,Xn,Yn,LineSpecn) plot(Y) plot(Y,LineSpec) plot(___,Name,Value) plot(ax,___) h plot(___) 说明 示例 plot(X,Y) 创建 Y 中数据对 X 中对应值的二维线图。 如果 …

MATLAB 画图

目录 图形对象属性 坐标轴 散点图 Line 属性 imagesc histogram 直方图 subplot 图像保存 其他 图形对象属性 set 设置图形对象属性 set(H,Name,Value)&#xff1a;为 H 标识的对象指定其 Name 属性的值 p plot(1:10); set(p,Color,red)% 更改特定线条的颜色gca 当…

【Matlab】MATLAB绘图

专题四 MATLAB绘图 绘图的目的是使数据可视化。 一 二维曲线 1. 函数plot() 在MATLAB中,函数plot()是最基本的绘图函数,利用它可以绘制出不同的二维曲线。函数plot()的基本用法: plot(x, y) % 其中,x和y分别用于存储x坐标和y坐标数据,通常x和y是长度相等的向…

Matlab 几种画图方式总结

函数形式/画图原理 1.显函数--- y f ( x ) 2.隐函数--- f (x , y ) 0 3.参数式--- x f ( x ) , y f ( y ) 4.极坐标--- 针对以上函数图像的绘制&#xff0c;有两种绘图方法&#xff1a; 1&#xff1a;找点画线&#xff1b; 2&#xff1a;根据定义域和函数关系画图&…

Matlab中的画图函数

目录 一、二维曲线和图形 1、二维图像基本命令plot (1). 曲线线型、颜色和标记点类型 (2). 设置曲线线宽、标记点大小&#xff0c;标记点边框颜色和标记点填充颜色等。 (3). 坐标轴设置 (4). 坐标轴刻度设置 (5). 图例 (6). 更多的设置 二、 图形的控制与表现 1&…

MATLAB-画图汇总

画图之前建议先想好自己要画什么样的图&#xff0c;再去找相关代码。 本文汇总了一些matlab画图代码和修饰指令。 画图指令 连线图-plot 连线图就是连接一个又一个的点&#xff0c;最后形成一个图&#xff08;折线图&#xff09;&#xff0c;但是当对进行限制&#xff0c;比…

matlab 找到数组中第一个不连续点_超全Matlab绘图方法整理

你好,我是 goldsunC让我们一起进步吧! 使用Matlab绘图 图像是结果的一种可视化表现,它能直观的体现你的结果,并且能体现你获得结果的准确性,在当前的大数据时代,在做数据分析的时候,将其可视化可以直观多维的展示数据,可以让人们更好的发现并且记住数据的特征,因此很多…