Java多线程-----定时器(Timer)及其实现

news2024/11/16 20:22:03

目录

一.定时器简介:

二.定时器的构造方法与常见方法:

三.定时器的模拟实现:

思路分析:

代码实现:


在开发中,我们经常需要一些周期性的操作,例如每隔几分钟就进行某一项操作,这时候我们就需要去设置个定时器,Java中最方便,最高效的实现方式是用java.util.Timer工具类,在通过调度java.util.TimerTask任务来完成

一.定时器简介:

①.Timer是一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者是定期的重复执行,实际上是个线程,定时调度所拥有的TimerTask任务

②.TimerTask是一个抽象类,它的子类由Timer安排为一次执行或者重复执行的任务,实际上就是一个拥有run方法的类,需要定时执行的代码放到run方法体内.

二.定时器的构造方法与常见方法:

①.构造方法:

②.常用方法:

注意事项:

①.上述方法中TimerTask是一个抽象方法,其子类是一个可以被Timer执行的任务,要执行的代码放在run()方法体内实现

②.schedule()与scheduleAtFixedRate()的区别? 首先schedule(TimerTask task,Date time)与schedule(TimerTask task,long delay)都只是单次执行操作,并不存在多次调用任务的情况,所以没有提供scheduleAtFixedRate方法的调用方式。它们实现的功能都一样,那区别在哪里呢? (1)schedule()方法更注重保持间隔时间的稳定:保障每隔period时间可调用一次。

(2)scheduleAtFixedRate()方法更注重保持执行频率的稳定:保障多次调用的频率趋近于period    时间,如果某一次调用时间大于period,下一次就会尽量小于period,以保障频率接近于period。

.每一个Timer仅对应一个线程,而不是每调用一次schedule就创建一个线程

④.Timer是线程安全的

代码实例1:

import java.util.Timer;
import java.util.TimerTask;
public class Mian {
    public static void main(String[] args) throws InterruptedException {
        //创建定时器线程对象同时设置名字
        Timer timer = new Timer("定时器线程");
        //传入要执行的任务,同时设置等待的时间
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                String current = Thread.currentThread().getName();
                System.out.println(current + " : 任务代码的执行区域~~~");
            }
        },2000);

       Thread.sleep(3000);
        System.out.println("执行结束");
        //结束定时器线程
        timer.cancel();
    }
}

运行结果:

代码实例2:

import java.util.Timer;
import java.util.TimerTask;
public class Mian2 {
    public static void main(String[] args) throws InterruptedException {
        //创建定时器线程对象同时设置名字
        Timer timer = new Timer("定时器线程");
        //传入要执行的任务,同时设置等待的时间
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                String current = Thread.currentThread().getName();
                System.out.println(current + " : 任务代码的执行区域~~~");
            }
        },1000,2000);

        Thread.sleep(6000);
        //结束定时器线程
        timer.cancel();
    }
}

运行结果:

三.定时器的模拟实现:

在了解了什么是定时器和定时器的使用之后,那么定时器是如何实现的呢?这里我们通过模拟实现定时器,来进一步加深对定时器的理解。注:这里我们仅仅模拟实现Timer类不带参数的构造方法和等待delay时间后要执行的任务类,以及核心方法schedule。

思路分析:

Timer类通过schedule添加等待delay时间后执行的代码,此时的任务可能不止一个,我们需要一个容器来存放这些任务,同时,为了公平起见,我们让先到达指定时间的任务优先执行,很自然的我们可以想到用优先级队列来存储这些任务,队首元素就是最先执行的任务.

同时,我们也需要一个线程来扫描队首元素,判断队首元素是否是需要执行的任务

综上,我们自己模拟实现的定时器需要完成以下任务:

①.用一个优先级队列存放要执行的任务,队首元素是最先执行的任务

②.任务中带有时间属性,记录任务所要执行的时间

③.用一个线程来扫描队首元素,判断队首元素是否需要执行

④.这里出现多个线程同时操作共享数据的代码,我们要解决线程安全问题

代码实现:

import java.util.*;
class MyTimerTask implements Comparable<MyTimerTask>{
    //要执行的任务代码
    private Runnable runnable;
    //ms级别的时间戳
    private long time;

    public MyTimerTask(Runnable runnable,long delay){
        this.runnable = runnable;
        //计算要执行的相对时间:当前时间+等待时间
        this.time = System.currentTimeMillis() + delay;
    }

    public void run(){
        runnable.run();
    }

    public long getTime(){
        return time;
    }
    //重写compareTo比较方法,按照时间的从小到大排序
    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.time - o.time);
    }

}
//模拟实现定时器
class MyTimer{
    private PriorityQueue<MyTimerTask> q = new PriorityQueue<>();
    //锁对象
    private static Object loker = new Object();
    //构造方法中启动线程,让线程进行判定与执行
    public MyTimer(){
        Thread t = new Thread(()->{
           try{
               while(true){
                   //将操作共享数据的队列锁起来,一次只允许一个线程进行操作,避免线程安全问题
                   synchronized (loker){
                       if(q.isEmpty()){
                               loker.wait();
                       }
                       MyTimerTask current = q.peek();
                       //如果当前时间超过(>=) 设定的时间,此时需要执行任务
                       if(System.currentTimeMillis() >= current.getTime()){
                           current.run();
                           //执行完成后,将任务从队列中删除
                           q.poll();
                       }else{
                           //否则不执行任务
                           loker.wait(current.getTime() - System.currentTimeMillis());
                       }
                   }
               }
           }catch (InterruptedException e) {
               e.printStackTrace();
           }
        });
        //开启线程
        t.start();
    }

    public void schedule(Runnable runnable,long delay){
        //将操作共享数据的队列锁起来,一次只允许一个线程进行操作,避免线程安全问题
       synchronized (loker){
           MyTimerTask myTimerTask = new MyTimerTask(runnable,delay);
           q.offer(myTimerTask);
           loker.notify();
       }
    }
}
//测试
public class Demo {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(()->{
            System.out.println("hello Thread" + ",3000  " + Thread.currentThread().getName());
        },3000);

        myTimer.schedule(()->{
            System.out.println("hello Thread" + ",2000  " + Thread.currentThread().getName());
        },2000);

        myTimer.schedule(()->{
            System.out.println("hello Thread" + ",1000  " + Thread.currentThread().getName());
        },1000);
    }
}

运行结果:

参考资料:

Java定时器的使用(Timer简介)_51CTO博客_java定时器

资源--timer的使用 - 牛李 - 博客园 (cnblogs.com)

结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

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

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

相关文章

【QT】常用控件-上

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 目录 &#x1f449;&#x1f3fb;QWidgetenabledgeometryrect制作上下左右按钮 window frame 的影响window titlewindowIcon代码示例: 通过 qrc 管理图片作为图标 windowOpacitycursor使用qrc自…

Python | Leetcode Python题解之第309题买卖股票的最佳时机含冷冻期

题目&#xff1a; 题解&#xff1a; class Solution:def maxProfit(self, prices: List[int]) -> int:if not prices:return 0n len(prices)f0, f1, f2 -prices[0], 0, 0for i in range(1, n):newf0 max(f0, f2 - prices[i])newf1 f0 prices[i]newf2 max(f1, f2)f0, …

【笔记】《冲击弹性波理论与应用》[2-2] 振动信号分析

1.前级硬件滤波 - 降噪 2.软件降噪 2.1 移动平滑滤波 2.1.1 移动平滑滤波的效果 2.2 经验模态分解法 2.1.1 效果 3 信号分析 除了FFT,最大熵和小波变换现在也很流行。 3.1 最大熵 3.1.1 与FFT的比对 3.2 相关性分析 3.2.1 自相关 3.2.2 互相关 3.3. 小波 非等周期信号 3…

《python语言程序设计》2018第6章第28题 掷骰子 两个色子,分别是1到6

2、3、12 玩家输 7、11玩家赢 4、5、6、8、9、10算1点&#xff0c;之后出7玩家输或者和上一次相同。def rolled(num_t):count 0still_win 0second_win 0still_lose 0second_lose 0while count < num_t:a_1 random.randint(1, 6)b_1 random.randint(1, 6)tTen a_1 b…

力扣-41.缺失的第一个正数

刷力扣热题–第二十五天:41.缺失的第一个正数 新手第二十五天 奋战敲代码&#xff0c;持之以恒&#xff0c;见证成长 1.题目简介 2.题目解答 做这道题有点投机取巧的感觉&#xff0c;要求时间复杂度O(N),且空间复杂度O(1)&#xff0c;那么就是尽可能的去找到更多的可能性&…

C语言程序设计之数组1

程序设计之数组1 问题1_1代码1_1结果1_1 问题1_2代码1_2结果1_2 问题1_3代码1_3结果1_3 问题1_4代码1_4结果1_4 问题1_5代码1_5结果1_5 问题1_1 函数 f u n fun fun 的功能是&#xff1a;移动一位数组中的内容&#xff0c;若数组中有 n n n 个整数&#xff0c;要求把下标从 …

软件测试生命周期、BUG描述与处理策略

软件测试的生命周期 需求分析&#xff1a;需求是否完整、是否正确 测试计划&#xff1a;确定由谁测试、测试的起止时间、设计哪些模块 测试设计、测试开发&#xff1a;写测试用例&#xff08;手工、自动化测试用例&#xff09;、编写测试工具 执行测试用例 测试评估&…

衢州骨伤科医院为98岁高龄老人做髋关节置换,患者第三天便下地行走

灵活迈步、周身整洁、双手提着两口袋鸡蛋......在清晨的菜市场里&#xff0c;王阿婆&#xff08;化名&#xff09;在人群里穿梭&#xff0c;买一些自己和女儿想吃的菜。如果没有看到她的脸&#xff0c;大家都以为她只有 60 多岁&#xff1b;再定睛一看&#xff0c;她虽然脸上布…

Token的原理及区别,以及与Cookie,Session之间的区别?

Token&#xff0c;特别是JSON Web Token&#xff08;JWT&#xff09;&#xff0c;也是一种用于管理用户状态和身份的机制&#xff0c;但它与Cookie和Session的工作方式有所不同。下面将详细解释Token如何管理用户状态和身份。 Token的工作原理 Token是一种无状态的认证机制&am…

QQ邮箱 + Kafka + Redis + Thymeleaf 模板引擎实现简单的用户注册认证

1. 前提条件 1.1 Redis 1.1.1 拉取 Redis 镜像 docker pull redis:latest 1.1.2 启动 Redis 容器 docker run --name my-redis -d -p 6379:6379 redis:latest1.2 Kafka 1.2.1 docker-compose.yml version: 3.8 services:zookeeper:image: "zookeeper:latest"h…

【C++入门(上)】—— 我与C++的不解之缘(一)

前言&#xff1a; 学完C语言和初阶数据结构&#xff0c;感觉自己又行了&#xff1f; 接下来进入C的学习&#xff0c;准备好接受头脑风暴吧。 一、第一个C程序 C 的第一个程序&#xff0c;梦回出学C语言&#xff0c;第一次使用C语言写代码&#xff1b;这里使用C写第一个C代码。 …

微信文件如何直接打印及打印功能在哪里设置?

在数字化时代&#xff0c;打印需求依旧不可或缺&#xff0c;但传统打印店的高昂价格和不便操作常常让人头疼。幸运的是&#xff0c;琢贝打印作为一款集便捷、经济、高效于一体的网上打印平台&#xff0c;正逐渐成为众多用户的首选。特别是通过微信小程序下单&#xff0c;更是让…

html+css前端作业和平精英2个页面(无js)

htmlcss前端作业和平精英2个页面&#xff08;无js&#xff09;有视频播放器等功能效果 下载地址 https://download.csdn.net/download/qq_42431718/89608232 目录1 目录2 项目视频 和平精英2个页面&#xff08;无js&#xff09;带视频播放 页面1 页面2

MinIO:高性能轻量云存储轻松搭建与springboot应用整合实践

简介 Minio是一款用Golang编写的开源对象存储套件&#xff0c;遵循Apache License v2.0开源协议。它虽然体积小巧&#xff0c;但性能出色。Minio支持亚马逊S3云存储服务接口&#xff0c;可以方便地与其他应用如NodeJS、Redis、MySQL等集成使用。 纠删码技术 Minio纠删码是一…

SpringBoot项目以及相关数据库部署在Linux常用命令

SpringBoot项目部署 1.IDEA打包&#xff0c;在IDEA终端&#xff0c;输入mvn clean install mvn clean package&#xff1a;删除目标文件夹、编译代码并打包mvn clean install&#xff1a;删除目标文件夹、编译代码并打包、将打好的包放置到本地仓库中 2.将项目target中的jar包…

LeetCode 面试经典 150 题 | 位运算

目录 1 什么是位运算&#xff1f;2 67. 二进制求和3 136. 只出现一次的数字4 137. 只出现一次的数字 II5 201. 数字范围按位与 1 什么是位运算&#xff1f; ✒️ 源自&#xff1a;位运算 - 菜鸟教程 在现代计算机中&#xff0c;所有数据都以二进制形式存储&#xff0c;…

【多模态大模型】 BLIP-2 in ICML 2023

一、引言 论文&#xff1a; BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models 作者&#xff1a; Salesforce Research 代码&#xff1a; BLIP-2 特点&#xff1a; 该方法分别使用冻结的图像编码器&#xff08;ViT-L/…

力扣SQL50 部门工资前三高的所有员工 自连接 子查询

Problem: 185. 部门工资前三高的所有员工 &#x1f468;‍&#x1f3eb; 参考题解 SELECTd.Name AS Department, -- 选择部门的名称&#xff0c;并将其别名为 Departmente1.Name AS Employee, -- 选择员工的姓名&#xff0c;并将其别名为 Employeee1.…

cmake之find_package命令详解

前言 find_package是cmake用来管理第三方库的一个命令。那这个命令有什么用呢&#xff1f;在实际项目开发中&#xff0c;我们肯定会使用到第三方库。那就需要在程序中&#xff0c;去指定库的位置和头文件位置&#xff0c;但库的安装位置&#xff0c;每个人都是不一样的&#x…

苍穹外卖day12(day09)---商家端订单管理模块

商家端订单管理模块&#xff1a; 订单搜索 产品原型 业务规则&#xff1a; 输入订单号/手机号进行搜索&#xff0c;支持模糊搜索 根据订单状态进行筛选 下单时间进行时间筛选 搜索内容为空&#xff0c;提示未找到相关订单 搜索结果页&#xff0c;展示包含搜索关键词的内容…