欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Timer定时器

程序员文章站 2022-07-14 13:18:21
...

主要两个要点:

  • 实现指定时间执行任务
  • 实现按照指定周期执行任务

定时器Timer的使用

JDK中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某个任务。

Timer类的主要作用就是设置计划任务,但封装任务的类却是TimerTask类。

执行计划任务的代码要放入TaskTimer的子类中,因为TimerTask是一个抽象类。

方法schedule(TimerTask task, Date time)的测试

schedule()方法的作用是在指定的日期执行一次某任务。

public class Run1 {

    /** Field timer */
    private static Timer timer = new Timer();

    /**
     * Method main
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            MyTask           task       = new MyTask();
            SimpleDateFormat sdf        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String           dateString = "2018-05-03 19:59:00";
            Date             dateRef    = sdf.parse(dateString);

            System.out.println("字符串时间,:" + dateRef.toLocaleString() + " 当前时间:" + new Date().toLocaleString());
            timer.schedule(task, dateRef);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Class MyTask
     *
     *
     * @version        1.0, 18/05/03
     * @author         tz    
     */
    public static class MyTask extends TimerTask {
        @Override
        public void run() {
            System.out.println("运行了,时间为:" + new Date());
        }
    }
} 

/*result:
字符串时间,:2018-5-3 19:59:00 当前时间:2018-5-3 20:01:12
运行了,时间为:Thu May 03 20:01:12 CST 2018
*/

程序运行结束,但进程还未被销毁。

创建一个Timer就是启动一个新线程,这个新启动的线程并不是守护进程,会一直运行下去。

也可以在Timer创建时1改为守护进程。代码如下:

public class Run1TimerDaemon {

    /** Field timer */
    private static Timer timer = new Timer(true);

    /**
     * Method main
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            MyTask           task       = new MyTask();
            SimpleDateFormat sdf        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String           dateString = "2018-05-04 08:46:00";
            Date             dateRef    = sdf.parse(dateString);

            System.out.println("字符串时间:" + dateRef.toLocaleString() + "当前时间:" + new Date().toLocaleString());
            timer.schedule(task, dateRef);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Class MyTask
     *
     *
     * @version        1.0, 18/05/04
     * @author         tz
     */
    public static class MyTask extends TimerTask {
        @Override
        public void run() {
            System.out.println("运行了!时间为:" + new Date());
        }
    }
}


/*result:
字符串时间:2018-5-4 8:46:00当前时间:2018-5-4 8:46:49
*/

程序运行后迅速结束当前进程,并且TimerTask中任务不再被运行,因为进程已经结束。

如果执行任务时间早于当前时间,则立即执行task任务。

Timer中允许有多个TimerTask任务。TimerTask是以队列的方式一个一个被执行的,所以执行那个时间爱你有可能和预期时间不一致,因为前面的任务有可能消耗较长时间。

public class Run2Later {

    /** Field timer */
    private static Timer timer = new Timer();

    /**
     * Method main
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            MyTask1          task1       = new MyTask1();
            MyTask2          task2       = new MyTask2();
            SimpleDateFormat sdf1        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat sdf2        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String           dateString1 = "2018-05-04 14:30:00";
            String           dateString2 = "2018-05-04 14:32:00";
            Date             dateRef1    = sdf1.parse(dateString1);
            Date             dateRef2    = sdf2.parse(dateString2);

            System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:" + new Date());
            System.out.println("字符串2时间:" + dateRef2.toLocaleString() + " 当前时间:" + new Date());
            timer.schedule(task1, dateRef1);
            timer.schedule(task2, dateRef2);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Class MyTask1
     *
     *
     * @version        1.0, 18/05/04
     * @author        tz
     */
    public static class MyTask1 extends TimerTask {
        @Override
        public void run() {
            try {
                System.out.println("1 begin 运行了,时间为:" + new Date());
                Thread.sleep(20000);
                System.out.println("1    end 运行了,时间为" + new Date());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * Class MyTask2
     *
     *
     * @version        1.0, 18/05/04
     * @author         tz
     */
    public static class MyTask2 extends TimerTask {
        @Override
        public void run() {
            System.out.println("2 begin 运行了,时间为:" + new Date());
            System.out.println("2 运行了,运行时间为:" + new Date());
            System.out.println("2    end 运行了,时间为" + new Date());
        }
    }
}


/*result:
字符串1时间:2018-5-4 14:30:00 当前时间:Fri May 04 14:37:59 CST 2018
字符串2时间:2018-5-4 14:32:00 当前时间:Fri May 04 14:37:59 CST 2018
1 begin 运行了,时间为:Fri May 04 14:37:59 CST 2018
1    end 运行了,时间为Fri May 04 14:38:19 CST 2018
2 begin 运行了,时间为:Fri May 04 14:38:19 CST 2018
2 运行了,运行时间为:Fri May 04 14:38:19 CST 2018 
2    end 运行了,时间为Fri May 04 14:38:19 CST 2018
*/

方法schedule(TimerTask task, Date firstTime, long period)

该方法的作用是在指定日期之后,按指定的间隔周期性的无限循环某一任务。

public class Run {

    /**
     * Method main
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            MyTask           task       = new MyTask();
            SimpleDateFormat sdf        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String           dateString = "2018-05-04 14:48:00";
            Timer            timer      = new Timer();
            Date             dateRef    = sdf.parse(dateString);

            System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:" + new Date().toLocaleString());
            timer.schedule(task, dateRef, 4000);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Class MyTask
     *
     *
     * @version        1.0, 18/05/04
     * @author         tz
     */
    public static class MyTask extends TimerTask {
        @Override
        public void run() {
            System.out.println("运行了! 时间为:" + new Date());
        }
    }
}

/*result:
字符串时间:2018-5-4 14:48:00 当前时间:2018-5-4 14:53:30
运行了! 时间为:Fri May 04 14:53:30 CST 2018
运行了! 时间为:Fri May 04 14:53:34 CST 2018
运行了! 时间为:Fri May 04 14:53:38 CST 2018
运行了! 时间为:Fri May 04 14:53:42 CST 2018
*/

task以周期为4s的状态下一直运行。

TimerTask的cancel方法

TimerTask的cancel方法是将自身从任务队列中清除掉。

public class Run2 {

    /**
     * Method main
     *
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            MyTaskA          task1      = new MyTaskA();
            MyTaskB          task2      = new MyTaskB();
            SimpleDateFormat sdf        = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String           dateString = "2018-05-04 14:48:00";
            Timer            timer      = new Timer();
            Date             dateRef    = sdf.parse(dateString);

            System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:" + new Date().toLocaleString());
            timer.schedule(task1, dateRef, 4000);
            timer.schedule(task2, dateRef, 4000);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    /**
     * Class MyTask
     *
     *
     * @version        1.0, 18/05/04
     * @author         tz
     */
    public static class MyTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("A 运行了! 时间为:" + new Date());
            this.cancel();
        }
    }


    /**
     * Class MyTaskB
     *
     *
     * @version        1.0, 18/05/04
     * @author         tz
     */
    public static class MyTaskB extends TimerTask {
        @Override
        public void run() {
            System.out.println("B 运行了! 时间为:" + new Date());
        }
    }
}


/*result:
字符串时间:2018-5-4 14:48:00 当前时间:2018-5-4 15:10:18
A 运行了! 时间为:Fri May 04 15:10:18 CST 2018
B 运行了! 时间为:Fri May 04 15:10:18 CST 2018
B 运行了! 时间为:Fri May 04 15:10:22 CST 2018
B 运行了! 时间为:Fri May 04 15:10:26 CST 2018
B 运行了! 时间为:Fri May 04 15:10:30 CST 2018
*/

Timer的cancel方法

Timer的cancel方法是清除所有的任务队列。

因为Timer的cancel()方法有时候并没有争抢到队列锁,所以TimerTask类中的任务会继续正常执行。

方法schedule(TimerTask task, long delay, long period)

该方法的作用是执行schedule(TimerTask task, long delay, long period)方法当前的时间为参考时间,在此时间的基础上延迟指定的毫秒数,再以某一时间间隔无限制的执行下去。

凡是方法中带有period参数的,都是无限循环执行TimerTask任务。

方法scheduleFixRate(TimerTask task, Date firstTime, long period)

方法scheduleFixRate(TimerTask task, Date firstTime, long period)和schedule()的区别在于不延时的情况。

使用schedule方法,如果执行任务的时间没有延迟,但下一任务的执行时间参考的是上一次任务的“开始”时间。

使用scheduleFixRate方法,参考的则是上一任务的“结束”时间。