【JavaEE】定时器

[复制链接]
发表于 2025-10-18 19:18:17 | 显示全部楼层 |阅读模式
博客末端有此篇博客的全部代码!!!
一、什么是定时器

   定时器(Timer)是一种用于在特定时间或按照肯定时间隔断实行任务的工具。它的焦点功能是答应步调在指定的时间点或周期性地实行代码,而不须要步调不绝轮询等候(是一种通过周期性查抄某个条件是否满足来等候事故发生的技能)。
  普通来讲:即在设定的时间时候实行某事的装备(比方闹钟,在指定的时间响铃),Java中的定时器会在到达设定的时间后,实行指定的代码
二、标准库中的定时器

2.1 Timer类的焦点方法schedule

标准库中提供定时器的类是Timer类,Timer类的焦点方法是schedule;

timer.schedule(TimerTask task,Date time);

timer.schedule(TimerTask task,long delay,long period);

timer.schedule(TimerTask task,Date firstTime,long period);

2.2 Timer类的构造方法


  1. public Timer() {
  2.     this("Timer-" + serialNumber());
  3. }
复制代码
以 Timer- +序列号作为定时器的名字。
  1. public Timer(boolean isDaemon) {
  2.         this("Timer-" + serialNumber(), isDaemon);
  3.     }
复制代码
是否将该定时器作为守卫线程实行。
  1. public Timer(String name) {
  2.         this(name, false);
  3.     }
复制代码
以name作为定时器的名字。
  1. public Timer(String name, boolean isDaemon) {
  2.         var threadReaper = new ThreadReaper(queue, thread);//可能是用于管理线程的生命周期
  3.         this.cleanup = CleanerFactory.cleaner().register(this, threadReaper);//可能是用于创建和管理资源的清除器
  4.         thread.setName(name);
  5.         thread.setDaemon(isDaemon);
  6.         thread.start();
  7.     }
复制代码
设置线程的名称和守卫状态,并启动线程以实行定时任务。
三、模拟实现定时器

思绪:

  • 创建一个类,表现一个任务
  • 创建一个聚集类,用来管理任务
  • 创建schedule方法,将任务方到队列当中
  • 创建线程,实行对列中的任务
3.1 创建一个类,表现一个任务

  1. class MyTimerTask implements Comparable<MyTimerTask> {
  2.     private Runnable runnable;
  3.     private long time;
  4.     //初始化TimerTask任务
  5.     public MyTimerTask(Runnable runnable, long time) {
  6.         this.runnable = runnable;
  7.         this.time = time;
  8.     }
  9.     public void run(){
  10.         runnable.run();
  11.     }
  12.     public long getTime() {
  13.         return time;
  14.     }
  15.     @Override
  16.     public int compareTo(MyTimerTask o) {
  17.         return (int) (this.time-o.time);
  18.     }
  19. }
复制代码
getTime()方法:获取任务实行的时间戳(和当前时间的时间戳举行比力)
compareTo()方法:创建优先级队列,须要将隔断当前时间近的任务排在靠前位置。
3.2 创建一个聚集类,用来管理任务

  1. private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
复制代码
3.3 创建schedule方法,将任务方到队列当中

  1.     //实现schedule方法,将任务放入队列当中
  2.     public void schedule(Runnable runnable, long time){
  3.         synchronized (lock){
  4.             queue.offer(new MyTimerTask(runnable, time));
  5.         }
  6.     }
复制代码
3.4 创建线程,实行对列中的任务

  1.     //创建线程,执行对队列中的任务
  2.     public MyTimer(){
  3.         Thread t = new Thread(()->{
  4.             while(true){
  5.                 synchronized (lock){
  6.                     while(queue.isEmpty()){
  7.                         continue;
  8.                     }
  9.                     MyTimerTask task=queue.peek();
  10.                     //获取当前时间的时间戳
  11.                     long curTime = System.currentTimeMillis();
  12.                     if(task.getTime()>curTime){
  13.                         continue;
  14.                     }else{
  15.                         task.run();
  16.                         queue.poll();
  17.                     }
  18.                 }
  19.             }
  20.         });
  21.         t.start();
  22.     }
复制代码
3.5 代码优化


   如果当前任务未到实行时间时,代码会不停重复实行队列的取出和塞回操纵,这种征象被称为"忙等"。为了更有用地使用CPU资源,我们须要使用壅闭式等候而不是忙等。
  第一时间我们会想到用sleep() 来壅闭等候,但是这里由于任务实行的不确定性,我们不知道设置多长时间,设置短了没效果,设置长了,当叫醒的时间,第一个代码已颠末了实行时间该怎么办?
这里就要用到刚学不就得wait()和notify()!!!
  1. import java.util.PriorityQueue;class MyTimerTask implements Comparable<MyTimerTask> {    private Runnable runnable;    private long time;    //初始化TimerTask任务    public MyTimerTask(Runnable runnable, long time) {        this.runnable = runnable;        this.time = time;    }    public void run() {        runnable.run();    }    public long getTime() {        return time;    }    @Override    public int compareTo(MyTimerTask o) {        return (int) (this.time - o.time);    }}class MyTimer {    Object lock = new Object();    //创建优先级队列,按时间次序次序实行    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
  2.     //创建线程,实行对队列中的任务    public MyTimer() {        Thread t = new Thread(() -> {            while (true) {                try {                    synchronized (lock) {                        while (queue.isEmpty()) {                            lock.wait();                        }                            MyTimerTask task = queue.peek();                            //获取当前时间的时间戳                            long curTime = System.currentTimeMillis();                            if (task.getTime() > curTime) {                                lock.wait(task.getTime() - curTime);                            } else {                                task.run();                                queue.poll();                            }                        }                    } catch(InterruptedException e){                        throw new RuntimeException(e);                    }                }            });            t.start();        }                //实现schedule方法,将任务放入队列当中        public void schedule (Runnable runnable,long time){            synchronized (lock) {                queue.offer(new MyTimerTask(runnable, time));                lock.notify();            }        }    }
复制代码
重要优化了两段代码:


  • schedule中的到场notify()来叫醒wait()方法
  • 将“忙等”优化掉,更有用的使用资源
四、扩展

上述模拟实现定时器恰当实行时间相差较大任务,如果在这个时间段有大量会集的任务须要上述代码实现的定时器处理处罚,此时就适适用基于循环数组实现的定时器处理处罚!(用二维链表实现的,将时间段分别为一小块一小块,分别将各个时间段的任务放入链表中)
定时器默认是单线程实行任务,如果一个任务实行时间过长,大概一起壅闭等候,大概全部任务共享同一个线程,大概会导致资源竞争题目。
那么这里我们就可以用我们刚学的线程池来资助我们办理这个题目!
  1. ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
复制代码
此篇博客的全部代码!!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表