我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java简单实现定时器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java简单实现定时器

本文实例为大家分享了Java简单实现定时器的具体代码,供大家参考,具体内容如下

一、定时器

定时器相当于一个任务管理器。有些任务可能现在执行, 有些任务可能过1个小时,甚至很久才会执行。定时器就是对这些任务进行管理监视, 如果一个任务执行时间到了,定时器就会将这个任务执行。 保证所有的任务都会在合适的时间执行。

二、定时器的实现

对于定时器的实现,我们可以划分为3个部分。

1、 使用一个Task类描述每一个任务(里面包含任务的执行方法, 定时时间)。
2、 使用优先级队列管理这些任务类。

2.1 我们都知道优先级队列底层实现是堆(以小根堆为例), 堆顶的元素是所有的元素的最小值。 我们以任务的定时时间为比较原则构建, 这样就可以保证堆顶元素的任务执行时间是最短的(这样的实现,我们需要在Task类内部定义比较规则-即重写Comparable接口的CompareTo方法)。

2.2 当一个任务执行完毕, 就会从优先级队列取出poll掉, 然后内部重新组织保证新的堆顶元素是定时时间最短的。

2.3 如果说堆顶的任务定时时间还没有到达(当然后续的任务定时时间肯定会更长,不会被执行)

3、使用一个线程循环扫描优先级队列, 相当于一个监控线程,循环判断堆顶任务是否满足执行时间。

三、定时器的组成

1、制定任务类Task

Task类包含任务的 执行方法 和 定时时间。

1.1 执行方法我采用封装Runnable中run方法实现, 这样做是为了后续添加任务时方便写执行逻辑。
1.2 定时时间就是long类型的变量
1.3 制定比较规则, 后续优先级队列中存放的是Task对象(而在内部构建时,需要比较两个Task对象的),对于对象的比较, 我们以对象的定时时间为规则, 制定小根堆。


static class Task implements Comparable<Task>{
        //Runnable类中有一个run方法, 通过这个方法实现任务的执行
        private Runnable command;
        //time表示执行的时间
        private long time;

        //构造方法
        public Task(Runnable command, long time) {
            this.command = command;
            this.time = System.currentTimeMillis() + time;  //将时间转化为绝对时间
        }

        //执行任务的逻辑
        public void run() {
            command.run();
        }

        //定义比较方法 - 方便后续的优先级队列构建

        @Override
        public int compareTo(Task o) {
            return (int)(this.time - o.time);
        }
    }

2、监管线程&定时器对象Timer

监管线程Worker中包含优先级队列(小根堆)queue 和 循环监管的流程。

Timer对象封装了监管线程Woker 和 任务的添加方法schedule()

关于监管线程的优化

2.1 循环监控存在一个弊端,那就是一直循环判断, 占用CPU资源。
(假如堆首任务的执行是1小时后, 再次期间监管线程会跑1小时循环判断。) 

解决方法: 可以通过线程阻塞和唤醒来解决。在下面代码有详细注释和实现。

2.1.1 如果任务1小时后执行, 我们让监管线程wait(1小时), 但在此期间如果有新的任务添加进来(可能新的任务需要等30分钟就可以执行,堆首元素发生变化) ,这时需要唤醒监管线程来重新判断。(由于wait和notify方法不在用一个类中实现, 我们通过一个Object(mailBox)来阻塞、唤醒)


//检测线程, 继承Thread类,重写内部run方法,属于线程的创建方法之一。
    static class Worker extends Thread {
     //优先级队列 - JUC包里面
        private PriorityBlockingQueue<Task> queue = null;
        //为了对监管线程进行阻塞和唤醒,采用同一对象
        private Object mailBox = null;
  
  //构造函数
        public Worker(PriorityBlockingQueue<Task> queue, Object mailBox) {
            this.queue = queue;
            this.mailBox = mailBox;
        }

        @Override
        public void run() {
            //实现具体的执行逻辑
            while(true) {
                try {
                    //1、取优先级队列的队首元素
                    Task task = queue.peek();
                    //2、比较队首的元素的时间是否大于当前时间
                    if(task == null) {
                        continue;
                    }
                    long curTime = System.currentTimeMillis();
                    if(task.time > curTime) {
                        //时间还没有到, 由于取出了任务, 需要重新放置回去
                        //优化1: 空循环等待 - wait(time) 让线程休眠time时间,然后在执行
                        //       如果在等待期间有新的任务添加, 这个时候我们唤醒线程, 继续判断(因为存在新的时间过短需要立即执行)
                        //       这个只需要添加一个新任务时, 唤醒即可
                        //优化2: 访问队首元素而不是取出, 防止无所谓的删除、插入。(维护优先级队列是有消耗的)
                        long gapTime = task.time - curTime;
                        synchronized (mailBox) {
                            mailBox.wait(gapTime);
                        }
                    }
                    else {
                        //直接执行
                        //如果执行到了, 则会删除头部元素, 调用任务的执行过程。
                        task = queue.take();
                        task.run();
                    }
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

    //定时器简单实现
    static class Timer {
        //定时器的实现步骤
        //1、用一个类描述任务
        //2、用优先级队列管理这些任务, 比较方法通过任务的制定时间,每次取队首元素
        //   队首元素是执行时间最近的
        private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
        //3、用一个线程来循环扫描当前的阻塞队列,判断队首的执行时间, 如果执行时间到了,那就执行。

        //4、创建一个Object对象,用于设置线程阻塞使用的, 存在线程阻塞, 添加任务时唤醒的操作
        private Object mailBox = new Object();

        //构造函数
        public Timer() {
            //创建线程
            Worker worker = new Worker(queue, mailBox);
            worker.start();
        }


        //4、提供一个方法, 让调用者能够把任务安排起来
        public void schedule(Runnable command, long time) {
            Task task = new Task(command, time);
            queue.put(task);
            synchronized (mailBox) {
                mailBox.notify();
            }
        }
    }

3、测试代码

其中添加了4个任务, 分别是2s、5s、7s、10s后执行。


public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝梦武一号任务执行, 执行代号:闪电;  定时时间:2s");
            }
        }, 2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝梦武二号任务执行, 执行代号:暴风;  定时时间:5s");
            }
        }, 5000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝梦武三号任务执行, 执行代号:狂风;  定时时间:7s");
            }
        }, 7000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("郝梦武三号任务执行, 执行代号:地震;  定时时间:10s");
            }
        }, 10000);
    }

4、测试结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java简单实现定时器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot简单实现定时器过程

这篇文章主要介绍了SpringBoot简单实现定时器过程,对于Java后端来说肯定实现定时功能肯定是使用到Spring封装好的定时调度Scheduled
2023-05-16

Java实现一个简单的定时器代码解析

定时的功能我们在手机上见得比较多,比如定时清理垃圾,闹钟,等等.定时功能在java中主要使用的就是Timer对象,他在内部使用的就是多线程的技术.Time类主要负责完成定时计划任务的功能,就是在指定的时间的开始执行某个任务.Timer类的作
2023-05-30

基于Python怎样实现简单的定时器

基于Python怎样实现简单的定时器,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。所谓定时器,是指间隔特定时间执行特定任务的机制。几乎所有的编程语言,都有定时器
2023-06-22

简单实现java音乐播放器

学习过java语言的你,或多或少,在某天突发奇想,想着用swing做一个音乐播放器。但是,发现很难找到,相关的java代码,或者你下载的代码有问题,或者你代码里面引入的类包找不到。为了解决自如此类的问题。在这儿,有如下的代码可以供大家参考。
2023-05-31

Android定时器Timer简单使用

在Android中,可以使用`Timer`类来创建定时器,实现定时执行某个任务的功能。以下是一个简单的使用示例:1. 创建一个`Timer`对象和一个`TimerTask`对象:```javaTimer timer = new Timer(
2023-10-12

Linux定时删除日志的简单实现方法

导语linux是一个很能自动产生文件的系统,日志、邮件、备份等。虽然现在硬盘廉价,我们可以有很多硬盘空间供这些文件浪费,让系统定时清理一些不需要的文件很有一种爽快的事情。 项目中会生成各种各样的日志,随着时间的推移,日志也是越来越多。超过一
2022-06-04

JS实现简单网页倒计时器

这篇文章主要为大家详细介绍了JS实现简单网页倒计时器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2022-11-13

Android利用SurfaceView实现简单计时器

自学了android有几个月了,跟着网上的节奏,应该早点写些博客来提高自己的水准的。但苦于技术水准始终不自信(也是不过关的结果吧),就一直只是将自己学习过程中的问题和重要的知识点写在自己的笔记文档中。 但,总感觉一个人写下来成就感还是欠缺了
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录