【Java | 多线程案例】定时器的实现

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Java系列专栏】【JaveEE学习专栏】
本专栏旨在分享学习JavaEE的一点学习心得,欢迎大家在评论区交流讨论💌

这里写目录标题

  • 一、Timer定时器
  • 二、Timer定时器的设计
  • 三、定时器的实现
  • 四、总结

一、Timer定时器

Java中,Timer类是用于计划和执行重复任务的类(Java标准库中确实提供了java.util.Timer类)。它可以在指定的时间间隔内重复执行一个任务,或者在指定时间点执行任务。

二、Timer定时器的设计

选择java.util包中的Timer类:
在这里插入图片描述

在这里插入图片描述
使用了Timer类的schedule()方法来安排一个任务在延迟3000毫秒后执行。在TimerTask的run()方法中,我们编写需要执行的具体任务逻辑
我们现在来了解一下TimerTask()这个抽象类(如下图):该类是一个抽象类,并且继承了Runnable方法创建了一个匿名内部类并实现了run()方法。这个匿名内部类可以被认为是继承了TimerTask抽象类,并提供了具体的实现代码。
在这里插入图片描述
调用timer.schedule()方法注册的任务,会由Timer内部的线程池去执行,而不是由调用schedule()方法的线程直接执行run()方法。
Timer类内部创建了一个线程池,用于执行注册的定时任务。当调用schedule()方法后,Timer会将传入的TimerTask对象添加到线程池中进行调度。

下面是一个简单的定时器程序,可以运行试试看:

import java.util.Timer;
import java.util.TimerTask;public class Demo22 {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello world!!!");}},3000);System.out.println("程序开始执行喽!!!");}
}

运行结果如下:
在这里插入图片描述
可以看到程序并没有结束进程,原因如下:
Timer内部有自己的线程,为了保证随时处理新安排的任务,此线程会一直持续的执行,即此线程影响了阻止来整个进程的结束。

定时器是支持多个任务同时执行的,请看:
在这里插入图片描述
在这里插入图片描述

三、定时器的实现

代码实现如下:

import java.util.Comparator;
import java.util.PriorityQueue;class MyTimerTask implements Comparable<MyTimerTask> {private long time; // 表示任务什么时候开始执行private Runnable runnable; // 表示具体任务是啥public MyTimerTask(Runnable runnable,long delay) {// 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); // time是long类型}
}// 这是定时器类的本体
class MyTimer {// 使用优先级队列来保存上面的N个任务private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();// locker是用来加锁的对象private Object locker = new Object();// 定时器的核心方法,即把要执行的任务添加到队列中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) {while(queue.isEmpty()) {// 队列为空时,此时不应该取这里的元素locker.wait();}MyTimerTask task = queue.peek();long curTime = System.currentTimeMillis();if(curTime > task.getTime()) {// 如果当前时间晚于任务的执行时间,就意味着我们要执行这个任务了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 Demo23 {public static void main(String[] args) {MyTimer timer = new MyTimer();timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello world! 3");}},3000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello world! 2");}},2000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello world! 1");}},1000);System.out.println("程序开始执行!!!");}
}

运行结果如下:
在这里插入图片描述

四、总结

Timer类是Java中的定时工具类,它可以帮助我们实现在指定时间执行指定任务的功能。Timer类提供了一个方法即schedule方法,我们可以通过schedule方法来注册一个任务并指定执行该任务的时间,当执行时间到的时候,Timer类内部的线程就会负责调用执行注册的任务。

另外我们可以通过优先级队列的方式来实现类似于Timer类这样的定时器。

本文到这里就结束了,希望友友们可以支持一下一键三连哈。嗯,就到这里吧,再见啦!!!

在这里插入图片描述

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

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

相关文章

x-cmd pkg | fzf - 命令行模糊查找器

目录 简介首次用户功能特点竞品和相关作品进一步阅读 简介 fzf 是一个由 Go 编写的命令行模糊搜索工具&#xff0c;用于在大量文本数据中快速定位和选择内容&#xff0c;可以与任何列表一起使用&#xff08;e.g. 文件、命令历史记录、进程、主机名、书签、git 提交等&#xff…

linux安装python

文章目录 前言一、下载安装包二、安装1.安装依赖2.解压3.安装4.软链接5.验证 总结 前言 本篇文章介绍linux环境下安装python。 一、下载安装包 下载地址&#xff1a;官方网站 我们以最新的标准版为例 二、安装 1.安装依赖 yum -y install openssl-devel ncurses-devel li…

UG装配-接触对齐

UG装配约束命令在如下位置 首选接触&#xff1a;含接触和对齐&#xff0c;自动判断两种类型 接触&#xff1a;约束对象使其曲面法向在相反方向&#xff0c;并共面或共线 对齐&#xff1a;约束对象使其曲面法向在同一方向&#xff0c;并共面或共线 自动判断中心/轴&#xff1…

【2023 —— 我和CSDN相遇的第一年】— “技术学习和个人成长的回顾与展望”

​ ​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 &#x1f38a;对2023的总结与回顾&#x1f38a; &#x1f3c5;获奖记录 &#x1f4da;学…

华为放出2023年最后一个大招!

▼最近直播超级多&#xff0c;预约保你有收获 跨年直播&#xff1a;《LLM构建生成式推荐系统及案例实战》 —1— 推出编程利器 CodeArts Snap 华为云研发大模型 CodeArts Snap 重磅推出&#xff0c;将软件工程 3.0 时代又向前推进了一步。 CodeArts Snap 是大模型智能开发辅助工…

V子型输出一串字符。。。

#include<stdio.h>int chars[100][2] {};//每行要出现的字符编码 int main() {int line;char start;char c, c1;scanf("%d %c",&line,&start);//输出多少行for (int i 0; i < line; i) {c A (start-A i)%26;c1 A (start - A 2*line-i-2) % 26…

DevOps持续交付之容器化CICD流水线

DevOps持续交付 随着DevOps⼤规模化的落地和应⽤&#xff0c;持续集成以及持续交付已经是⼀种常态的。CI指的是持续集成&#xff0c;使⽤的开源⼯具是Jenkins&#xff0c;CD指的是持续交付和持续部署&#xff0c;⼀个完整的软件开发⽣命周期为: 主要流程可以具体为: 构建阶段…

游戏服务器安全需要注意什么方面需要搭配什么防护策略

服务器主机安全需要注意什么方面,首先需要知道服务器安全威胁有哪些 服务器安全威胁是指可能导致服务器遭受攻击、数据泄露或服务中断的各种风险和威胁。以下是一些常见的服务器安全威胁&#xff1a; 1. 恶意软件和病毒&#xff1a;服务器可能感染恶意软件、病毒或蠕虫&#…

java生产设备效率管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web生产设备效率管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为ac…

《Spring Cloud学习笔记:微服务保护Sentinel + JMeter快速入门》

Review 解决了服务拆分之后的服务治理问题&#xff1a;Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互&#xff0c;基于网关的过滤器解决了登录校验的问题 流量控制&#xff1a;避免因为突发流量而导致的服务宕机。 隔离和降级&#xff1a…

C#中使用as关键字将对象转换为指定类型

目录 一、定义 二、示例 三、生成 使用as关键字可以将对象转换为指定类型&#xff0c;与is关键字不同&#xff0c;is关键字用于检查对象是否与给定类型兼容&#xff0c;如果兼容则返回true&#xff0c;如果不兼容则返回false。而as关键字会直接进行类型转换&#xff0c;如果…

机器学习--主成分分析 PCA

特征维度约减 特征约减的目的是将高维特征向量映射到低维子空间中。比如&#xff1a; 给定n个样本&#xff08;每个样本维度为p维&#xff09;{x1,....xn} 通过特征变换/投影矩阵实现特征空间的压缩: 高维数据 为何要维度约减? 数据压缩和存储&#xff1a;高维数据通常需要占用…