JavaEE之线程(9) _定时器的实现代码

前言

 定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”。 达到一个设定的时间之后,就执行某个指定好的代码,比如:

在这里插入图片描述

 在受上述场景中,当客户端发出去请求之后, 就要等待响应,如果服务器迟迟没有响应,也不清楚,这个请求就没发过去? 响应丢了?服务器出问题了?
 对于客户端来说,不能无限的等,需要有一个最大的期限,到达这个最大的期限之后,是重新再发一遍,还是彻底放弃,还是什么其他的方式。
类似于以上场景就需要用到定时器。


一、标准库中的定时器

 在标准库中提供了一个 Timer 类,它的核心方法为 schedule 。

schedule方法 包含两个参数:

  1. 第一个参数指定即将要执行的任务代码;
  2. 第二个参数指定多长时间之后执行 (单位为毫秒)。

参考代码如下:

Timer timer = new Timer();
timer.schedule(new TimerTask() {
	@Override
	public void run() {
		System.out.println("hello");
	}
}, 3000);

二、实现一个定时器

在实现一个定时器(Timer)前,我们需要考虑三个问题

  1. Timer 中需要有一个线程,扫描任务是否到时间,可以执行了;
  2. 需要有一个数据结构,把所有的任务都保存起来;
  3. 还需要创建–人类,通过类的对象来描述一个任务(至少要包含任务内容和时间);

2.1 定时器的构成

1. 一个带优先级的阻塞队列;

为社么要带优先级呢?
 因为阻塞队列中的任务都有各自的执行时刻 (delay)。最先执行的任务一定是 delay 最小的。使用带优先级的队列就可以高效的把这个 delay 最小的任务找出来。

2. 队列中的每个元素是一个 Task 对象;
3.Task 中带有一个时间属性, 队首元素就是即将要执行的对象;
4. 同时有一个 worker 线程一直扫描队首元素, 看队首元素是否需要执行。

2.2实现过程

定时器的完整实现代码:

package Timer9;

import java.util.PriorityQueue;

/**
 * @author Zhang
 * @date 2024/5/1016:43
 * @Description:
 */
//通过这个类,描述了一个任务
class MyTimerTak implements Comparable<MyTimerTak>{
    //要有一个要执行的任务
    private Runnable runnable;
    //执行任务的时间
    private  long time;
    // 此处的delay,就是schedule方法传入的相对时间
    public MyTimerTak(Runnable runnable, long delay ) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis()+delay;
    }

    @Override
    public int compareTo(MyTimerTak o) {
        //这样写,就是让队首元素是最小时间的值
        return (int)(this.time - o.time);
    }

    public long getTime(){
        return  time;
    }

    public  Runnable getRunnable(){
        return  runnable;
    }
}

//自己的定时器
class  MyTimer{
    //使用一个数据结构,保存所有要安排的任务
    PriorityQueue<MyTimerTak> queue = new PriorityQueue<>();

    //使用这个ui想作为锁对象
    private Object locker = new Object();
    public void schedule(Runnable runnable,long delay){
        synchronized (locker){
            queue.offer(new MyTimerTak(runnable, delay));
        }

    }

    //扫描线程
    public MyTimer(){
        //创建一个线程
        Thread t = new Thread(()->{
            while (true){
                try{
                    synchronized (locker){
                        //不要使用if 作为wait的判定条件,应该使用while
                        //使用 while 的目的是为了在 wait被唤醒的时候,再次确认一下条件
                        while(queue.isEmpty()){
                            //使用wait等待
                             //这里的wait,需要另外的线程唤醒
                            //添加了新任务,就会被唤醒
                            locker.wait();
                        }
                        MyTimerTak tak = queue.peek();
                        //比较当前的队首是否可以执行元素
                        long curTime = System.currentTimeMillis();
                        if (curTime >= tak.getTime()){
                            //当前时间已经达到了人物事件,就可以执行任务了
                            tak.getRunnable().run();
                            //任务执行结束,就可以从队列中删除了
                            queue.poll();
                        }else {
                            //当前时间还没达到任务时间,暂时不执行任务
                            locker.wait(tak.getTime() - curTime);

                        }
                    }

                } catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }


}

定时器的调用和演示:

public class Demo2 {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3000");
            }
        },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2000");
            }
        },2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("1000");
            }
        },1000);

    }
}

总结

 以上就是今天要讲的内容,本文仅仅简单介绍定时器的使用场景,标准库中的定时器,定时器的实现代码。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv10最全使用教程(含ONNX和TensorRT推理)

论文题目&#xff1a;YOLOv10: Real-Time End-to-End Object Detection 研究单位&#xff1a;清华大学 论文链接&#xff1a;http://arxiv.org/abs/2405.14458 代码链接&#xff1a;https://github.com/THU-MIG/yolov10 作者提供的模型性能评价图&#xff0c;如下&#xff1a;…

基于灰狼优化算法优化RBF(GWO-RBF)的数据回归预测(多输入多输出)

代码原理及流程 基于灰狼优化算法优化多输入多输出&#xff08;MIMO&#xff09;的RBF神经网络的数据回归预测&#xff0c;可以采取以下步骤&#xff1a; 1. 数据准备&#xff1a;准备包含多个输入特征和多个输出目标的数据集&#xff0c;确保数据已经经过预处理和归一化。 …

盲人社区生活支持体系:织就一张温暖的网

在当今社会&#xff0c;构建一个全面、包容的盲人社区生活支持体系成为了推动社会进步、保障残障人士权益的重要议题。随着科技的不断革新&#xff0c;一款名为“蝙蝠避障”的辅助软件走进了盲人的日常生活&#xff0c;它如同一位无形的向导&#xff0c;通过实时避障与拍照识别…

Failed to load property source from location ‘classpath:/application.yml‘

总帮客户二开 经常会遇到这种问题 网上的解决办法都是刷新maven (对我没用&#xff01;) 我的解决办法是修改编码&#xff01;

PLSQL连接Linux Oracle21c

PLSQL连接Linux Oracle21c 一、安装PLsql 下载官网 https://www.allroundautomations.com/registered-plsqldev/ 二、Oracle Instant Client下载 使用plsql连接oracle的时候是需要本地先安装oracle客户端&#xff0c;英文名就是Oracle Instant Client。 官方下载地址&…

初识java——javaSE (6)接口的实现——比较器与深拷贝,浅拷贝

文章目录 前言一 比较器1.1 关于两个对象的比较1.2 Comparable接口&#xff1a;1.3 Arrays.sort方法的实现1.4 比较器的实现Comparator接口 二 深拷贝与浅拷贝2.1 浅拷贝&#xff1a;Cloneable接口&#xff1a;clone方法&#xff1a;实现拷贝&#xff1a;浅拷贝&#xff1a; 2.…

【C++】list容器

目录 一.list容器介绍 二.C中list的基本组成 三.list容器相关接口的模拟实现 1.push_back() 2.迭代器的begin()和end() 3.insert() 4.erase() 5.pop_front() 6.pop_back() 7.size() 8.empty() 9.析构~list()和清除数据clear() 10.拷贝构造 11.赋值运算 四.模拟…

分享几张漂亮的linux kde主题

分享几张漂亮的linux kde主题&#xff1a;在系统设置的全局主题内下载。

SpringBoot——整合Redis

目录 Redis 创建Commodity表 启动MySQL和Redis 新建一个SpringBoot项目 pom.xml application.properties Commodity实体类 ComMapper接口 ComService业务层接口 ComServiceImpl业务接口的实现类 ComController控制器 RedisConfig配置类 SpringbootRdisApplication启…

c++|多态

c|多态 1 多态的概念2 多态的定义及其实现2.1 满足多态的条件2.2 虚函数2.3 虚函数的重写2.4 析构函数适合加virtural吗2.4 C11 override 和 final2.5 三个概念的对比 3 多态的原理4 抽象类4.1 概念4.2 纯虚函数 1 多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是…

微信小程序实现容器图片流式布局功能,配合小程序原生框架使用。

小程序实现容器图片流式布局功能&#xff0c;因为目前论坛上也有很多博主出过类似的文章&#xff0c;这里我就以一个小白角度去讲一下如何实现的吧。给作者一点点鼓励&#xff0c;先点个赞赞吧&#x1f44d;&#xff0c;蟹蟹&#xff01;&#xff01; 目标 实现下方效果图 技术…

HarmonyOS鸿蒙应用开发——安装与配置

今天脑子又抽风&#xff0c;前端转完学后端之后&#xff0c;今天大周末早上醒来突然又想学鸿蒙了&#xff0c;刚好有个比赛需要用到鸿蒙&#xff0c;于是乎我就随便点开b站看了一下鸿蒙视频&#xff0c;然后马上来写这篇博客&#xff0c;后续我的鸿蒙的博客可能会跳着、不连续地…

springboot集成达梦数据库8

springboot集成达梦数据库8 官方文档&#xff1a;[https://eco.dameng.com/document/dm/zh-cn/start/java-development.html](https://eco.dameng.com/document/dm/zh-cn/start/java-development.html) 引入maven依赖 <!--添加数据库驱动安装包--> <dependency> …

十六进制转十进制

十六进制转十进制 在玩编程的时候常会碰到十六进制转换的问题。对于专业的大佬大咖这不是问题&#xff0c;小人物总会有些麻烦。我在研究调色板时也遇到进制转换问题。前些时在本站发了十进制转十六进制的博文&#xff0c;今再写十六进制转十进制的转换方法。供大家参考。 下面…

awk编辑器

目录 工作原理 命令格式 普通格式 BEGIN格式 语句循环格式 awk常见的内建变量&#xff08;可直接用&#xff09; 按行打印行内容 统计行数量 按字段输出文本 通过管道、双引号调用 Shell 命令 awk编辑器是一种流编辑器 工作原理 逐行读取文本,默认以空格或tab键为分…

光环P3O不错的一个讲座

光环P3O不错的一个讲座&#xff0c;地址&#xff1a;https://apphfuydjku5721.h5.xiaoeknow.com/v2/course/alive/l_663dc840e4b0694c62c32d1d?app_idapphfuydJkU5721&share_fromu_5c987304d8515_wH2E5HgCgx&share_type5&share_user_idu_5c987304d8515_wH2E5HgCgx…

AIGC-风格迁移-“DEADiff:稳定可控的文本到图像风格化扩散模型 “-CVPR2024

DEADiff: An Efficient Stylization Diffusion Model with Disentangled Representations 代码&#xff1a;https://tianhao-qi.github.io/DEADiff/ 论文&#xff1a;https://arxiv.org/pdf/2403.06951 本文介绍了一种名为DEADiff的方法&#xff0c;旨在解决基于扩散的文本到图…

又翻车了!谷歌急于手动删除搜索中的奇怪AI答案|TodayAI

谷歌公司近日确认&#xff0c;正在“迅速采取行动”删除一些AI工具的奇怪回应。社交媒体上充斥着谷歌新AI概览产品&#xff08;AI Overview&#xff09;说出奇怪话语的例子&#xff0c;从告诉用户在披萨上涂胶水到建议他们吃石头。这次混乱的AI发布导致谷歌不得不手动禁用某些搜…

车灯合面合壳密封使用UV胶的优缺点是什么呢?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

车灯合面合壳密封使用UV胶的优缺点是什么呢? 车灯合壳密封使用UV胶的优缺点如下&#xff1a; 优点&#xff1a; 快速固化&#xff1a;UV胶通过紫外线照射可以在短时间内迅速固化&#xff0c;大大缩短了车灯制造的工艺流程时间&#xff0c;提高了生产效率。高度透明&#xff…

二叉树——进阶(递归创建,非递归,广度优先,翻转,深度,对称)

二叉树——进阶 二叉树的递归创建非递归前中后序遍历非递归前序遍历非递归中序遍历非递归后序遍历 广度优先遍历二叉树&#xff08;层序遍历&#xff09;翻转二叉树 二叉树深度最大深度最小深度 对称二叉树 二叉树的递归创建 1&#xff0c;二叉树是一种结构相对固定的数据&…