多线程-定时器

目录

1.定时器是什么

2.标准库中的定时器

 3.实现定时器

3.1 MyTimer类

  1.首先Timer 类提供的核⼼接⼝为 schedule, ⽤于注册⼀个任务, 并指定这个任务多⻓时间后执⾏.

   2.Timer 实例中, 通过 PriorityQueue 来组织若⼲个 Task 对象. 通过 schedule 来往队列中插⼊⼀个个 Task 对象.

3.Timer 类中存在⼀个 worker 线程, ⼀直不停的扫描队⾸元素, 看看是否能执⾏这个任务.

 3.2MyTimerTask类

3.3main类


1.定时器是什么

       定时器也是软件开发中的⼀个重要组件. 类似于⼀个 "闹钟". 达到⼀个设定的时间之后, 就执⾏某个指定好的代码. 定时器是⼀种实际开发中⾮常常⽤的组件. ⽐如⽹络通信中, 如果对⽅ 500ms 内没有返回数据, 则断开连接尝试重连. ⽐如⼀个 Map, 希望⾥⾯的某个 key 在 3s 之后过期(⾃动删除). 类似于这样的场景就需要⽤到定时器.

2.标准库中的定时器

标准库中提供了⼀个 Timer 类. Timer 类的核⼼⽅法为 schedule .

schedule 包含两个参数. 第⼀个参数指定即将要执⾏的任务代码, 第⼆个参数delay指定多⻓时间之后 执⾏ (单位为毫秒)

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

 3.实现定时器

定时器的构成
⼀个带优先级队列(不要使⽤ PriorityBlockingQueue, 容易死锁!)
队列中的每个元素是⼀个 Task 对象.
Task 中带有⼀个时间属性, 队⾸元素就是即将要执⾏的任务
同时有⼀个 worker 线程⼀直扫描队⾸元素, 看队⾸元素是否需要执⾏

3.1 MyTimer类

  1.首先Timer 类提供的核⼼接⼝为 schedule, ⽤于注册⼀个任务, 并指定这个任务多⻓时间后执⾏.

      
public void schedule(Runnable runnable , long delay){
         synchronized (locker){
            MyTimerTask task = new MyTimerTask(runnable, delay);
            queue.offer(task);//用于将指定元素插入到队列尾部,如果队列已满则返回 false
            //添加新元素后,唤醒扫描线程的wait
            locker.notify();
        }
    MyTimerTask task = new MyTimerTask(runnable, delay);创建了一个MyTimerTask
对象,用于表示一个任务。它接受两个参数:runnable和delay。

         参数runnable:是一个Runnable对象,表示要执行的具体任务逻辑。你可以通过实现Runnable接口并重写run()方法来定义自己的任务逻辑。

        参数delay:是一个long类型的值,表示任务的延迟时间。它指定了从当前时间开始,到任务执行时间的时间间隔(以毫秒为单位)。在构造MyTimerTask对象时,会根据当前时间和延迟时间计算出任务的绝对执行时间,并保存在time成员变量中。

   2.Timer 实例中, 通过 PriorityQueue 来组织若⼲个 Task 对象. 通过 schedule 来往队列中插⼊⼀个个 Task 对象.

//负责扫描任务队列,执行任务的线程。
    private Thread t = null;
    // 任务队列
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    //弄一个锁对象
    public Object locker = new Object();

     public void schedule(Runnable runnable , long delay){
         synchronized (locker){
            MyTimerTask task = new MyTimerTask(runnable, delay);
            queue.offer(task);//用于将指定元素插入到队列尾部,如果队列已满则返回 false
            //添加新元素后,唤醒扫描线程的wait
            locker.notify();
        }

    }

   PriorityQueue:是Java集合框架中的一个实现了优先级队列的类。它可以用于存储元素,并按照一定的优先级来访问和删除元素。

     同时我们为了线程的安全性,创建了一个锁对象。

3.Timer 类中存在⼀个 worker 线程, ⼀直不停的扫描队⾸元素, 看看是否能执⾏这个任务.

      

public MyTimer(){
         t = new Thread(()->{
            //扫描线程就需要循环的反复的扫描队首元素,然后判定队首元素是不是时间到了
            //如果没有到,啥也不干
            //如果到了,就执行这个任务并且把这个任务从队列中删除掉。
            while (true){
                try {
                synchronized (locker){
                    if(queue.isEmpty()){
                        //暂不处理
                            locker.wait();
                    }
                    MyTimerTask task = queue.peek();
                    //获取到当前时间
                    long curTime = System.currentTimeMillis();
                    if(curTime >= task.getTime()){
                        //当前时间已经到了任务时间,就可以执行任务了
                        queue.poll();//从队列中获取队头元素,并将其从队列中移除。
                        task.run();
                    }else {
                        //当前时间还没有到,暂时先不执行
                        //continue;//“忙等”,没有意义,应该把cpu资源让出来
                        //Thread.sleep 不能用sleep会错过新的任务
                        locker.wait(task.getTime() - curTime);
                    }
                }//解锁
                     } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
         });
         t.start();
    }

     如果队列为空的话我们就暂时不出力,用wait 等待一下。我们用curtime来接受当前的时间。

 3.2MyTimerTask类

       Task 类⽤于描述⼀个任务(作为 Timer 的内部类). ⾥⾯包含⼀个 Runnable 对象和⼀个 time(毫秒时间戳) 这个对象需要放到 优先队列 中. 因此需要实现 Comparable 接⼝.
class MyTimerTask  implements Comparable<MyTimerTask>{
    //在什么时间点来执行这个任务
    //此约定这个 time 是一个 ms 级别的时间戳
    private long time;
    //实际任务要执行的代码
    private Runnable runnable;

    public  long getTime(){
        return time;
    }
    public MyTimerTask(Runnable runnable , long delay){
        this.runnable = runnable;
        //计算一下真正要执行任务的绝对时间(使用绝对时间,方便判定任务是否到达时间的)
        this.time = System.currentTimeMillis() + delay;
    }
    public void run(){
        runnable.run();
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return  (int) (this.time - o.time);
        //return (int)(o.time - this.time);//试一试是哪一个减哪一个
    }
}

       private Runnable runnable:

       我们将传入的runnable参数保存到成员变量runnable中。当任务到达执行时间时,定时器会调用MyTimerTask对象的run()方法来执行具体的任务逻辑,而run()方法实际上就是调用runnable对象的run()方法。这样一来,我们就可以通过传入不同的Runnable对象来定义不同的任务逻辑。

      this.time = System.currentTimeMillis() + delay;

     System.currentTimeMillis() 返回当前系统时间的毫秒表示,表示从1970年1月1日00:00:00 GMT开始到现在的时间间隔。delay 是任务的延迟时间,以毫秒为单位。通过将当前系统时间和延迟时间相加,我们可以得到任务的绝对执行时间。

3.3main类

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

       首先创建了一个 MyTimer 对象 timer。然后,通过调用 timer.schedule() 方法来添加三个任务。每个任务都是通过匿名内部类实现的 Runnable 接口,并重写了 run() 方法在 run() 方法中,分别打印出不同的消息,表示任务的内容。每个任务都具有不同的延迟时间:3000毫秒、2000毫秒和5000毫秒。这意味着第一个任务将在程序启动后的3秒钟之后执行,第二个任务将在2秒钟之后执行,第三个任务将在5秒钟之后执行。

                                                          希望大家多多支持!!! 

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

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

相关文章

中缀转后缀

概念 什么是后缀表达式&#xff1f; 后缀表达式&#xff0c;其实就是一个中缀表达式 AOB > ABO &#xff08;A、B是式子、O 为运算符&#xff09;&#xff0c;将运算符向后放 中转后举例 中缀表达式&#xff1a;&#xff08;a b&#xff09;* c - (d / c) 首先&#xff…

jupyter notebook找不到自己创建的环境 无法识别 解决方法

问题描述&#xff1a; 这是最近遇到的一个关于Anaconda的小问题。 用conda创建一个名为 pytorch 的环境想学习pytorch&#xff0c;安装完一切之后在 jupyter 中找不到 pytorch 这个虚拟环境&#xff0c;与之相关的库也都无法调用 解决方法&#xff1a; 实际上是由于在虚拟环境…

DevOps落地笔记-12|API管理:微服务时代的必备工具

上一课时主要介绍了使用持续集成这个实践来保证开发中的软件处于可工作的状态&#xff0c;解决的是开发后期才集成导致的无法集成或功能无法使用的问题。 最近几年&#xff0c;软件架构也在不断升级&#xff0c;逐渐采用前后端分离、微服务的体系结构。前后端分离使得前端和后…

使用API有效率地管理Dynadot域名,使用API进行域名平台内转移(Push)命令

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

非精线搜索步长规则Armijo规则Goldstein规则Wolfe规则

非精确线搜索步长规则 在数值优化中&#xff0c;线搜索是一种寻找合适步长的策略&#xff0c;以确保在目标函数上获得足够的下降。如最速下降法&#xff0c;拟牛顿法这些常用的优化算法等&#xff0c;其中的线搜索步骤通常使用Armijo规则、Goldstein规则或Wolfe规则等。 设无…

介绍一款可以对书签分类的手机浏览器

DT浏览器是一款专为手机安卓系统设计的小型、快速且安全的浏览器&#xff0c;其中一个显著特点是对安卓系统的各个版本具有良好的自适应性&#xff0c;这意味着用户无论使用的是新型还是旧型手机&#xff0c;都可以顺畅地使用DT浏览器。为了提高用户的使用便利性&#xff0c;DT…

牛客寒假训练营H题

思路&#xff1a;找出所有m的子集&#xff0c;加到价值中&#xff0c;找出最大价值即可。 代码&#xff1a; void solve(){int n, m;cin >> n >> m;vector<pii>a(n 1);for(int i 1;i < n;i )cin >> a[i].first >> a[i].second;int ans 0…

2024年【安全员-C证】新版试题及安全员-C证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证新版试题参考答案及安全员-C证考试试题解析是安全生产模拟考试一点通题库老师及安全员-C证操作证已考过的学员汇总&#xff0c;相对有效帮助安全员-C证复审考试学员顺利通过考试。 1、【多选题】《企业安全…

【初中生讲机器学习】4. 支持向量机算法怎么用?一个实例带你看懂!

创建时间&#xff1a;2024-02-02 最后编辑时间&#xff1a;2024-02-03 作者&#xff1a;Geeker_LStar 你好呀~这里是 Geeker_LStar 的人工智能学习专栏&#xff0c;很高兴遇见你~ 我是 Geeker_LStar&#xff0c;一名初三学生&#xff0c;热爱计算机和数学&#xff0c;我们一起加…

华为机考入门python3--(5)牛客5-进制转换

分类&#xff1a;数字 知识点&#xff1a; 十六进制转int num int(hex_num, 16) int转十六进制 hex_num hex(num) 题目来自【牛客】 hex_num input().strip() dec_num int(hex_num, 16) print(dec_num) by 软件工程小施同学

python爬虫5

1.selenium交互 无页面浏览器速度更快 #配置好的自己不用管 from selenium import webdriverfrom selenium.webdriver.chrome.options import Optionschrome_options Options()chrome_options.add_argument(‐‐headless)chrome_options.add_argument(‐‐disable‐gpu)# path…

2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模

上一篇已经对赛题进行详细分析了&#xff0c;而且大方向和基本的模型已经确定完毕&#xff0c;数据集都已经找到了&#xff0c;现在最重要的就是要分析风暴数据集以及建立时序预测模型&#xff0c;使用气候模型预测的数据&#xff0c;评估气候变化对未来极端天气事件频率和强度…

世界顶级汽车品牌源代码遭泄露 详解源代码凭据安全解决方案

源代码凭据安全&#xff0c;您别忽视 !!! 一、事件回顾 2024年1月29日&#xff0c;RedHunt 实验室的研究员Lohit爆料&#xff1a;某世界顶级的豪华汽车品牌源代码面临泄露风险&#xff01;人为错误致GitHub令牌事故引发重大安全担忧。 RedHunt Labs在一次互联网扫描时&#x…

顺序表:数据结构的建筑积木

朋友们大家好啊&#xff0c;本节内容我们进入数据结构的第二节&#xff0c;顺序表有关内容&#xff0c;同步我们会学习计组原理与cpp相关知识&#xff0c;求三连啊&#xff01; 本节我们重点探讨动态顺序表关于插入数据和删除数据的多种情况的分析 顺序表 线性表顺序表静态顺序…

2024年2月4日 十二生肖 今日运势

小运播报&#xff1a;2024年2月4日&#xff0c;星期日&#xff0c;农历腊月廿五 &#xff08;癸卯年乙丑月戊戌日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;兔、马、虎 需要注意&#xff1a;牛、鸡、龙 喜神方位&#xff1a;东南方 财神方位&#xff1a;正…

linux中的makefile

(码字不易&#xff0c;关注一下吧w~~w&#xff09; makefile文件是用来管理项目文件&#xff0c;通过执行make命令&#xff0c;make就会解析并执行makefile文件。 命名&#xff1a;makefile或者Makefile 规则&#xff1a; 目标文件&#xff1a;依赖文件 &#xff08;tab)命…

Jetpack Compose系列(3)-使用列表

使用列表 在 View 体系中&#xff0c;创建自定义布局必须扩展 ViewGroup 并实现测量和布局函数。在 Compose 中&#xff0c;只需使用 Layout 可组合项编写一个(布局)函数即可。上一篇文章我们详细介绍了Column()和Row()这两各横向布局&#xff0c;这里我们继续介绍其他布局。 …

LeetCode:42. 接雨水

42. 接雨水 1&#xff09;题目2&#xff09;思路3&#xff09;代码4&#xff09;结果 1&#xff09;题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height …

Jmeter学习系列之四:测试计划元素介绍

测试计划元素 JMeter包含各种相互关联但为不同目的而设计的元素。在开始使用JMeter之前&#xff0c;最好先了解一下JMeter的一些主要元素。 注意:测试计划包含至少一个线程组。 以下是JMeter的一些主要组件: 测试计划&#xff08;Plan&#xff09;线程组(Thread Group)控制器…

每日OJ题_算法_模拟③_力扣6. Z 字形变换

目录 力扣6. Z 字形变换 解析代码 力扣6. Z 字形变换 6. Z 字形变换 难度 中等 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时&#xff0c;排列如下&#xff…