《Java-SE-第二十五章》之定时器

前言

在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!”

博客主页:KC老衲爱尼姑的博客主页

博主的github,平常所写代码皆在于此

共勉:talk is cheap, show me the code

作者是爪哇岛的新手,水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


定时器

什么是定时器?

​   Java 中的定时器就类似于一个"闹钟",达到一个设定的时间之后,就会执行某个指定的好的代码。就像在学校有早八的课,会设置早上7:30的闹钟提醒自己去上课。所以的当我们使用定时器的时候,需要的设定一个时间和设置好一个对应的任务。Java标准库中提供了带有定时功能的类Timer。

Timer

​  在Java8中,Timer提供了四个构造方法,这些构造方法可以去指定现成的名字和指定定时器内部的线程是否为守护线程。Java中一共有两种线程,一种用户线程,即前台线程,典型的就是main线程,另一种是守护线程(后台线程),典型的是GC(垃圾回收器)。

构造方法
    /**
     * 无参构造方法,默认定时器关联的线程不是守护线程,线程的名字也是默认值
     */
    public Timer() {
        this("Timer-" + serialNumber());
    }

    /**
     * 指定定时器内部的线程是否为守护线程,如果是,参数则为true
     */
    public Timer(boolean isDaemon) {
        this("Timer-" + serialNumber(), isDaemon);
    }

    /**
     * 指定定时器关联线程的名称,线程类型默认是非守护线程
     */
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }

    /**
     * 指定定时器关联线程的名称和线程类型
     */
    public Timer(String name, boolean isDaemon) {
        thread.setName(name);
        thread.setDaemon(isDaemon);
        thread.start();
    }
常见方法
  /**
    * 指定任务,延迟多久执行该任务
   */
public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, 0);
    }

    /**
     * 指定任务,指定任务的执行时间
     */
    public void schedule(TimerTask task, Date time) {
        sched(task, time.getTime(), 0);
    }

    /**
     * 连续执行指定任务,延迟时间,连续执行任务的时间间隔,毫秒为单位
     */
    public void schedule(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, -period);
    }

    /**连续执行指定任务,第一次任务的执行时间,连续执行任务的时间间隔
     * 
     */
    public void schedule(TimerTask task, Date firstTime, long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), -period);
    }

使用演示:

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

public class TimerDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,要上课了");
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,要上课了,要迟到了");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,太阳都出来了");
            }
        },3000);

    }
}

运行结果:

在这里插入图片描述

TimerTask类就是专门描述定时器任务的一个抽象类,它实现了Runnable接口。

定时器的简单实现

  定时器的作用是个某个任务设置时间,并让该任务到点执行。由此可知,我们需要一个类来描述任务,并且需要一个基于小根堆的优先级的阻塞队列来管理任务,因为阻塞队列中的任务都有各自的时刻,最先执行的一定是时间最小的,使用优先级的对列就就可以高效的把这个时刻最小的任务取出来执行。

public  class MyTask implements Comparable<MyTask>{
        private Runnable command;
        private long time;

    public long getTime() {
        return time;
    }

    public MyTask(Runnable command, long time) {
            this.command = command;
            //time中存的是绝对时间,超过该时间的任务就应该被执行。
            this.time = time;
        }

        @Override
        public int compareTo(MyTask o) {
            //谁的时间小排在前面
            return (int)(time-o.time);
        }
        public void run() {
            command.run();
        }
}

  实现定时器类,其核心方法就是schedule,其目的就是为了安排任务。定时器还需要中存在一个 worker 线程, 一直不停的扫描队首元素, 看看是否能执行这个任务,如果这个任务还没有到执行时间,那么这个线程必须等待,在此是用wait等待,因为中途提交的任务可能是最早执行的,这个时候就需要提前唤醒线程,这个唤醒操作使用notify,使用了wait和notify就再提供专门的锁对象来加锁。

import java.util.concurrent.PriorityBlockingQueue;

public class MyTime {
    /**
     * 锁对象
     */
    private final Object lock = new Object();
    /**
     * 每次执行任务,优先执行时间在前的任务,也就是每次都得从优先级对列中取出时间最小的任务
     */
    private static final PriorityBlockingQueue<MyTask>  queue = new PriorityBlockingQueue<>();

    /**
     * 安排任务
     * @param runnable
     * @param after
     */
    public void schedule(Runnable runnable,long after) {
        MyTask myTask = new MyTask(runnable,after);
        queue.offer(myTask);
        synchronized (lock) {
             //每次当新任务加载到阻塞队列时,需要中途唤醒线程,因为新进来的任务可能是最早需要执行的
            lock.notify();
        }
    }
    public MyTime(){
        Worker worker = new Worker();
        worker.start();
    }


    private  class Worker extends Thread{
        @Override
        public void run() {
            while (true) {
                try {
                    MyTask task = queue.take();
                    long currentTime = System.currentTimeMillis();
                    if (task.getTime() > currentTime) {
                      synchronized (lock) {
                          //任务被执行的时间还没有到,把任务塞回队列
                          queue.put(task);
                          //设置指定等待时间 wait
                          lock.wait(task.getTime()-currentTime);
                      }
                    }else {
                        //时间到了,可以执行任务
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }
}

使用演示:


import java.util.TimerTask;

public class MyTimeDemo {
    public static void main(String[] args) {
        MyTime myTime = new MyTime();
        myTime.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,要上课了");
            }
        }, 1000);
        myTime.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,要上课了,要迟到了");
            }
        }, 2000);
        myTime.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("起床了,太阳都出来了");
            }
        }, 3000);

    }
}

运行结果:
在这里插入图片描述


​ 各位看官如果觉得文章写得不错,点赞评论关注走一波!谢谢啦!。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潇潇雨声迟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值