【JavaEE】【多线程】定时器

news2024/11/28 12:48:09

目录

  • 一、定时器简介
    • 1.1 Timer类
    • 1.2 使用案例
  • 二、实现简易定时器
    • 2.1 MyTimerTask类
    • 2.2 实现schedule方法
    • 2.3 构造方法
    • 2.4 总代码
    • 2.5 测试

一、定时器简介

定时器:就相当于一个闹钟,当我们定的时间到了,那么就执行一些逻辑。

1.1 Timer类

Java的标准库中提供了在java.util包下的Timer类作为定时器。
有如下的构造方法:
四种:

  1. timer() 无参构造;
  2. timer(boolean isDaemon) 创建的线程都是后台线程;
  3. timer(String name) 给定时器中创建的线程名字;
  4. timer(String name, boolean isDaemon) 创建的线程都是后台线程,也给定时器中创建的线程名字。

在Timer类中的核心方法是schedule方法。

  1. schedule(Timer task, Date time) 到达time时刻后执行task任务;
  2. schedule(Timer task, Date firstTime, long period) 到达time时刻后重复执行task任务,每次相隔period时间;
  3. schedule(Timer task, long delay) 在delay时间后执行task任务;
  4. schedule(Timer task, long delay, long period) 在delay时间后重复执行task任务,每次相隔period时间;
  5. scheduleAtFixedRate(Timer task, Date firstTime, long period) 到达time时刻后重复执行task任务,每次执行period时间;
  6. scheduleAtFixedRate(Timer task, long delay, long period) 在delay时间后重复执行task任务,每次执行period时间;

schedule的第一个参数是TimerTask类,这是一个实现了Runnable接口的抽象类。

1.2 使用案例

我们使用schedule方法来打印不同时间执行不同内容。

import java.util.Timer;
import java.util.TimerTask;

public class Demo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3000ms后执行");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("1000ms后执行");
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2000ms后执行");
            }
        },2000);
    }
}

结果如下:会按照等待时间由小到大打印内容,并且执行完之后并不会结束,这是因为这些线程是前台线程。

二、实现简易定时器

自己实现的定时器主要要考虑下面几个内容:

  1. 设计一个类表示任务,对应TimerTask类;
  2. 使用优先级队列来组织多个任务,每次根节点都是等待时间最短的任务;
  3. 实现schedule方法,把任务添加到队列中;
  4. 额外创建一个线程,负责执行队列中的任务,根据时间来执行(即判断是否到了该执行的时间了)。

2.1 MyTimerTask类

这个类中需要:

  • 将要执行的任务,和任务要执行的时刻记录下来,
  • 并且这个任务还要有通过时刻比较得方法(即实现Comparator接口,重写CompareTo方法),便于后面存储进优先级队列。

代码:

class MyTimerTask implements Comparable<MyTimerTask>{
    //记录任务
    private Runnable task = null;
    //记录执行任务的时刻
    private long current = 0;

    public MyTimerTask(Runnable task, long current) {
        this.task = task;
        this.current = current;
    }

    public Runnable getTask() {
        return task;
    }

    public long getCurrent() {
        return current;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.current - o.current);
    }
}

2.2 实现schedule方法

我们实现schedule方法:

  • 只需要将当前的任务传入队列中即可。
  • 将参数Runnable的任务和时刻用来创建MyTimerTask类,在入队即可。
  • 我们还要使用notify为后面的线程中因为队列为空调用wait进入阻塞状态提供唤醒。

代码:

private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();

public void schedule(Runnable task, long delay) {
        synchronized (this) {
            MyTimerTask myTimerTask = new MyTimerTask(task, System.currentTimeMillis() + delay);
            queue.offer(myTimerTask);
            this.notify();
        }
    }

2.3 构造方法

在构造方法中额外创建一个线程,负责执行队列中的任务,根据时间来执行(即判断是否到了该执行的时间了)。

  • 我们在最外层使用一层死循环来不断去读取队列中的任务。
  • 如果队列空了,那么我们就出这次循环,但是如果使用continue的话,还是会在循环的去判断直到队列不为空为止。这样的消耗很高,我们可以使用wait等待schedule方法入队列后;来唤醒这个线程。
  • 如果没有到达执行时间,我们也要出这次循环,但是使用continue也会导致在从现在这个时刻到执行时刻之间一直进行无意义的执行上面的代码,消耗很高,我们这里直接使用带参数的wait方法等待还需要的时间即可。
  • 到达执行时间直接执行任务并出队列即可。
  • 最后不要忘记启动这个线程。

代码:

public MyTimer() {
        Thread thread = new Thread(()-> {
            try {
                while(true) {  //循环拿任务,直到任务队列为空
                    synchronized (this) {
                        while (queue.isEmpty()) {  //任务队列为空
                            this.wait();
                        }
                        MyTimerTask task = queue.peek();
                        
                        if(task.getCurrent() > System.currentTimeMillis()) { //没到执行时间 
                            this.wait(task.getCurrent() - System.currentTimeMillis());
                        } else {
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }

2.4 总代码

总代码如下:

class MyTimerTask implements Comparable<MyTimerTask>{
    //记录任务
    private Runnable task = null;
    //记录执行任务的时刻
    private long current = 0;

    public MyTimerTask(Runnable task, long current) {
        this.task = task;
        this.current = current;
    }

    public Runnable getTask() {
        return task;
    }

    public long getCurrent() {
        return current;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.current - o.current);
    }
    public void run() {
        task.run();
    }


}

class MyTimer {
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();

    public void schedule(Runnable task, long delay) {
        synchronized (this) {
            MyTimerTask myTimerTask = new MyTimerTask(task, System.currentTimeMillis() + delay);
            queue.offer(myTimerTask);
            this.notify();
        }
    }
    public MyTimer() {
        Thread thread = new Thread(()-> {
            try {
                while(true) {  //循环拿任务,直到任务队列为空
                    synchronized (this) {
                        while (queue.isEmpty()) {  //任务队列为空
                            this.wait();
                        }
                        MyTimerTask task = queue.peek();

                        if(task.getCurrent() > System.currentTimeMillis()) { //没到执行时间
                            this.wait(task.getCurrent() - System.currentTimeMillis());
                        } else {
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }
}

2.5 测试

如果在main中执行下面这样的代码,也使用schedule方法来打印不同时间执行不同内容,会与上面使用案例的结果一样。

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

结果如下:会按照等待时间由小到大打印内容,并且执行完之后并不会结束,这是因为这些线程是前台线程。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TVM前端研究--Relay

文章目录 深度学习IR梳理1. IR属性2. DL前端发展3. DL编译器4. DL编程语言Relay的主要内容一、Expression in Relay1. Dataflow and Control Fragments2. 变量3. 函数3.1 闭包3.2 多态和类型关系3.3. Call4. 算子5. ADT Constructors6. Moudle和Global Function7. 常量和元组8.…

SSL/TLS 密码套件漏洞分析以及修复方法

1. 前言 在当今数字化时代&#xff0c;网络安全至关重要。SSL/TLS 协议作为保障网络通信安全的重要手段&#xff0c;广泛应用于各类网络应用中。然而&#xff0c;如同任何技术一样&#xff0c;SSL/TLS 也并非绝对安全&#xff0c;存在着一些可能被攻击者利用的漏洞。本文将深入…

stm32入门教程--DMA 超详细!!!

目录 简介 工作模式 1、数据转运DMA 2、ADC扫描模式DMA 简介 工作模式 1、数据转运DMA 这个例子的任务是将SRAM的数组DataA&#xff0c;转运到另一个数组DataB中&#xff0c;这个基本结构里的各个参数应该如何配置呢&#xff1f; 首先是外设站点和存储器站点的起始地址、…

大数据新视界 -- 大数据大厂之大数据重塑影视娱乐产业的未来(4 - 3)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

TIFS-2024 细粒度表示和重组在换衣行人重识别中的应用

总体结论 本文提出了一种新的细粒度表示与重构&#xff08;FIRe2&#xff09;框架&#xff0c;用于解决布变人重识别问题。通过细粒度特征挖掘和属性重构&#xff0c;FIRe2在不依赖任何辅助信息的情况下&#xff0c;实现了最先进的性能。该方法在多个基准数据集上取得了显著的…

基于JSP的篮球系列网上商城系统【附源码】

基于JSP的篮球系列网上商城系统 效果如下&#xff1a; 系统首页界面 商品信息界面 购物车界面 购物车界面 管理员登录界面 管理员功能界面 用户注册界面 我的收藏界面 研究背景 21世纪&#xff0c;我国早在上世纪就已普及互联网信息&#xff0c;互联网对人们生活中带来了无限…

重学SpringBoot3-怎样优雅停机

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-怎样优雅停机 1. 什么是优雅停机&#xff1f;2. Spring Boot 3 优雅停机的配置3. Tomcat 和 Reactor Netty 的优雅停机机制3.1 Tomcat 优雅停机3.2 Reac…

MySQL 数据库备份与恢复全攻略

MySQL 数据库备份与恢复全攻略 引言 在现代应用中&#xff0c;数据库是核心组件之一。无论是个人项目还是企业级应用&#xff0c;数据的安全性和完整性都至关重要。为了防止数据丢失、损坏或意外删除&#xff0c;定期备份数据库是必不可少的。本文将详细介绍 MySQL 数据库的备…

Cesium基础-(Entity)-(Billboard)

里边包含Vue、React框架代码 2、Billboard 广告牌 Cesium中的Billboard是一种用于在3D场景中添加图像标签的简单方式。Billboard提供了一种方法来显示定向的2D图像,这些图像通常用于表示简单的标记、符号或图标。以下是对Billboard的详细解读: 1. Billboard的定义和特性 B…

DEVOPS: 容器与虚拟化与云原生

概述 传统虚拟机&#xff0c;利用 hypervisor&#xff0c;模拟出独立的硬件和系统&#xff0c;在此之上创建应用虚拟机是一个主机模拟出多个主机虚拟机需要先拥有独立的系统docker 是把应用及配套环境独立打包成一个单位docker 是在主机系统中建立多个应用及配套环境docker 是…

ansible开局配置-openEuler

ansible干啥用的就不多介绍了&#xff0c;这篇文章主要在说ansible的安装、开局配置、免密登录。 ansible安装 查看系统版本 cat /etc/openEuler-latest输出内容如下&#xff1a; openeulerversionopenEuler-24.03-LTS compiletime2024-05-27-21-31-28 gccversion12.3.1-30.…

img 标签的 object-fit 属性

设置图片固定尺寸后&#xff0c;可以通过 object-fit 属性调整图片展示的形式 object-fit: contain; 图片的长宽比不变&#xff0c;相应调整大小。 object-fit: cover; 当图片的长宽比与容器的长宽比不一致时&#xff0c;会被裁切。 object-fit: fill; 图片不再锁定长宽…

基于边缘计算的智能门禁系统架构设计分析

案例 阅读以下关于 Web 系统架构设计的叙述&#xff0c;回答问题1至问题3。 【说明】 某公司拟开发一套基于边缘计算的智能门禁系统&#xff0c;用于如园区、新零售、工业现场等存在来访被访业务的场景。来访者在来访前&#xff0c;可以通过线上提前预约的方式将自己的个人信息…

数学建模清风——论文写作方法教程笔记

PS&#xff1a;本文不讲LateX的使用&#xff01;讲述论文的写作方法 首页&#xff1a;论文标题摘要关键词 一、问题重述 二、问题分析 三、模型假设 四、符号说明 五、模型的建立与求解 六、模型的分析与检验 七、模型的评价、改进与推广 八、参考文献 附录 首页&#xff…

Laravel5 抓取第三方网站图片,存储到本地

背景 近期发现&#xff0c;网站上的部分图片无法显示&#xff0c; 分析发现&#xff0c;是因为引用的第三方网站图片&#xff08;第三方服务器证书已过期&#xff09; 想着以后显示的方便 直接抓取第三方服务器图片&#xff0c;转存到本地服务器 思路 1. 查询数据表&#xff0…

自适应神经网络架构:原理解析与代码示例

个人主页&#xff1a;chian-ocean 文章专栏 自适应神经网络结构&#xff1a;深入探讨与代码实现 1. 引言 随着深度学习的不断发展&#xff0c;传统神经网络模型在处理复杂任务时的局限性逐渐显现。固定的网络结构和参数对于动态变化的环境和多样化的数据往往难以适应&#…

《Python游戏编程入门》注-第4章1

《Python游戏编程入门》的第4章是“用户输入&#xff1a;Bomb Cathcer游戏”&#xff0c;通过轮询键盘和鼠标设备状态实现Bomb Cathcer游戏。 1 Bomb Cathcer游戏介绍 “4.1 认识Bomb Cathcer游戏”内容介绍了Bomb Cathcer游戏的玩法&#xff0c;即通过鼠标来控制红色“挡板”…

【Java基础】2、Java基础语法

f2/fnf2&#xff1a;选中点中的文件名 ​​​​​​​ 1.注释 为什么要有注释&#xff1f; 给别人和以后的自己可以看懂的解释 注释含义 注释是在程序指定位置的说明性信息&#xff1b;简单理解&#xff0c;就是对代码的一种解释 注释分类 单行注释 //注释信息 多行注释…

Spring Boot 应用开发概述

目录 Spring Boot 应用开发概述 Spring Boot 的核心特性 Spring Boot 的开发模式 Spring Boot 在企业应用开发中的优势 结论 Spring Boot 应用开发概述 Spring Boot 是由 Pivotal 团队开发的一个框架&#xff0c;基于 Spring 框架&#xff0c;旨在简化和加速基于 Spring …

微信小程序 - 动画(Animation)执行过程 / 实现过程 / 实现方式

前言 因官方文档描述不清晰,本文主要介绍微信小程序动画 实现过程 / 实现方式。 实现过程 推荐你对照 官方文档 来看本文章,这样更有利于理解。 简单来说,整个动画实现过程就三步: 创建一个动画实例 animation。调用实例的方法来描述动画。最后通过动画实例的 export 方法…