千家信息网

Java定时器如何实现

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇"Java定时器如何实现"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Java定
千家信息网最后更新 2025年11月07日Java定时器如何实现

这篇"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{        //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 queue = null;        //为了对监管线程进行阻塞和唤醒,采用同一对象        private Object mailBox = null;    //构造函数        public Worker(PriorityBlockingQueue 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 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);    }

以上就是关于"Java定时器如何实现"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

任务 时间 线程 方法 定时器 队列 优先级 元素 监管 对象 循环 阻塞 内容 小时 代号 就是 管理 规则 逻辑 小根 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 修改linux数据库编码 南沙区软件开发报名 软件开发项目投标书 数据库怎样修改字段的排列规则 省委网络安全委员会第二次会议 随访中心数据库建设 郑州百知互联网科技有限公司 移动商务软件开发方向 软件开发管理最核心的问题是 网络安全新闻稿作文 多台服务器组建docker 如何访问企业数据库 网络安全服务需要哪些技能 辅助管理服务器推荐 大理互联网科技好吗 南京有招聘软件开发实习生的 栖霞微信小程序软件开发推荐 武装突袭3服务器进不去了 易语言怎么给数据库添加数据 如何入侵网站数据库 如果要禁止修改数据库中的表 网络技术标准第几代 华为云怎么购买软件开发平台 ibm 服务器错误代码 网络安全监控税收分类编码 你们单位网络安全做到位了吗 日本官方的专利数据库 对象关系数据库混合管理 计算机网络技术的市场 数据库工程师 历年真题
0