JDK1.8 java.util.Timer类探索

一、Timer支持多任务

        java.util.Timer类的作者是大名鼎鼎的Josh Bloch,他可是Java集合框架的作者,谷歌首席架构师。最近一直想研究定时任务,所以就从最最古老的类开始使用吧。

        从API文档里看到一个延迟的方法,就是延迟执行任务。我这里的每个任务都是打印任务名称。但是延迟的时间从5秒递减到1秒。为Timer中添加5个任务。运行结果是什么呢?

 public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(getRandomTask(5), 5000);
        timer.schedule(getRandomTask(4), 4000);
        timer.schedule(getRandomTask(3), 3000);
        timer.schedule(getRandomTask(2), 2000);
        timer.schedule(getRandomTask(1), 1000);
    }

    private static TimerTask getRandomTask(int num) {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务" + num);
            }
        };
        return task;
    }

       从运行结果来看,看来Timer类内部很可能维护了一个"任务队列",并且知道这个任务在具体得某一刻开始执行。延迟最小的任务1只延迟了1秒,所以第一个打印出来。相反,任务5虽然在主函数的第一行执行,但是延迟5秒后才最后打印出来。所以可以确定,一个Timer对象能够执行多个任务。

拨云见日

        Timer类能支持执行多个任务,并且是按照顺序执行。

二、再谈Timer类异常处理

        下面的代码几乎与上面得相同,只是在构造任务的时候加了一个限制,就是说如果执行了任务3会出错。运行结果又会是什么呢?

public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(getRandomTask(5), 5000);
        timer.schedule(getRandomTask(4), 4000);
        timer.schedule(getRandomTask(3), 3000);
        timer.schedule(getRandomTask(2), 2000);
        timer.schedule(getRandomTask(1), 1000);
    }

    private static TimerTask getRandomTask(int num) {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务" + num);
                if (num == 3) {
                    String error = "任务" + num + "报错";
                    throw new RuntimeException(error);
                }
            }
        };
        return task;
    }

             我把本次运行结果与上次运行结果拿出来对比一下。任务3报错,实际上就会让本该执行的任务4与任务5执行不了。换句话说,Timer类在多线程并行处理任务的时候,只要其中一个定时任务出错,那么其它任务也都会自动停止运行。这在生产库上是绝对不允许的。或许这也是Timer被废弃的重要缺陷之一吧。

本次程序运行结果:

JDK1.8 java.util.Timer类探索_第1张图片

上次程序运行结果        

 拨云见日

        Timer类在执行多个任务的时候,如果其中一个任务出错,并且没有捕获异常的话,其它任务也会终止执行。所以为了防止这种情况的出现,需要为每个任务使用try--catch语句。

三、Timer应对死循环

        如果某个定时任务出现了死循环,那么会对其它定时任务造成影响吗?

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(getRandomTask(5), 5000);
        timer.schedule(getRandomTask(4), 4000);
        timer.schedule(getRandomTask(3), 3000);
        timer.schedule(getRandomTask(2), 2000);
        timer.schedule(getRandomTask(1), 1000);
    }

    private static TimerTask getRandomTask(int num) {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务" + num);
                //死循环
                while (true) {
                }
            }
        };
    }

JDK1.8 java.util.Timer类探索_第2张图片

拨云见日

        Timer中允许有多个TimerTask任务,并且是按照顺序执行的,不能同时执行两个任务。
        任务如果前一个时间执行过长,很可能导致后面的任务延时执行。
        如果前一个任务出现阻塞,可能造成后面的任务都得不到执行,导致死锁。

四、MisFire错过执行的补救情况

         (1)如果只执行一次的定时任务错过执行,Timer会怎么样呢?

-- 运行时间: 17:55:00 分
timer.schedule(getRandomTask(2), todayAt(17,38,0));

        从结果来看,schedule方法为"只执行一次的定时任务,并且这个任务已经过了应该执行的时间",Timer调度会追加执行一次。

        

        (2)如果是按照固定频率执行的定时任务会怎么样?

-- 运行时间18:03:00,从18点开始,每30秒执行一次。        
timer.scheduleAtFixedRate(getRandomTask(1), todayAt(18, 0, 0), 30000);

JDK1.8 java.util.Timer类探索_第3张图片

        从结果来看,scheduleAtFixedRate方法具有追赶性。如果计划时间在过去,那么从过去到现在这段时间间隔内的任务也会周期的全部追加执行。

      (3)另外一个按照固定频率执行的定时任务

-- 运行时间 18:06
timer.scheduleAtFixedRate(getRandomTask(1), todayAt(18, 0, 0), 30000);

        运行结果:如果有错过的任务,那么在启动的时候立即执行一次,然后以当前时间为开始时间,按照固定得频率执行定时任务。
 

拨云见日

       Timer类对于只执行一次的定时任务,如果任务执行时间错过了,那么在启动的时候,会追加执行一次。

       Timer类对于按照固定频率执行的定时任务

                     scheduleAtFixedRate方法的MissFire策略是   追加执行所有错过的任务

                     schedule方法的MissFire策略是立即执行一次,并以当前时间为基准,按照固定的频率执行任务

你可能感兴趣的:(#,从头开始学Quartz,跟着大宇学SpringBoot)