Timer和TimerTask定时器使用

Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次。 
TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。具体的任务在TimerTask中run接口中实现。 
通过Timer中的schedule方法启动定时任务。

一、运行定时器
启动一个定时器实质是启动一个线程 
1、在指定日期运行定时器任务,只运行一次   

public static void main(String[] args) throws ParseException {
        String sdate = "2018-02-14";
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");
        Date date = sf.parse(sdate);

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, date); //在指定的日期运行一次定时任务
    /*如果date日期在今天之前,则启动定时器后,立即运行一次定时任务run方法*/
    /*如果date日期在今天之后,则启动定时器后,会在指定的将来日期运行一次任务run方法*/
    }


2、在距当前时刻的一段时间后运行定时器任务,只运行一次   

public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, 5000); //指定启动定时器5s之后运行定时器任务run方法,并且只运行一次
    }


3、在指定的时间后,每隔指定的时间,重复运行定时器任务   

public static void main(String[] args) throws ParseException {
        String sdate = "2018-02-10";
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");
        Date date = sf.parse(sdate);

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, date, 2000);
        /*如果指定的date时间是当天或者今天之前,启动定时器后会立即每隔2s运行一次定时器任务*/
        /*如果指定的date时间是未来的某天,启动定时器后会在未来的那天开始,每隔2s执行一次定时器任务*/
    }


4、在距当前时刻的一段指定距离后,每隔指定时间运行一次定时器任务   

public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, 5000, 2000);
        /*当启动定时器后,5s之后开始每隔2s执行一次定时器任务*/
    }


二、停止定时器
停止定时器实质是终止Timer的线程。默认情况下,创建的Timer线程会一直执行,如果要停止的话主要有以下四种方法终止Timer线程:

调用Timer的cancel方法;
把Timer线程设置成Daemon守护线程,当所有的用户线程结束后,那么守护线程也会被终止;
当所有的任务执行结束后,删除对应Timer对象的引用,线程也会被终止;
调用System.exit方法终止程序

举例用cancel方法终止Timer线程   

 public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("系统正在运行……");
//              timer.cancel(); //可以在任何时刻调用cancel方法终止timer线程
            }
        }, 5000, 2000);

        /*如果主线程不休眠一段时间,就执行了cancel方法,那么定时器还没来得及执行就会被关闭*/
        Thread.sleep(6000);
        timer.cancel();
    }


三、启动任务schedule 与 scheduleAtFixedRate的区别
1、schedule   

 public static void main(String[] args) throws ParseException {
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
        Date date = sf.parse("2018-02-12 18:33:00");

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println(new Date() + "系统正在运行……");
            }
        }, date, 10*1000);

    }


运行,输出如下:

Mon Feb 12 18:35:41 CST 2018系统正在运行……
Mon Feb 12 18:35:51 CST 2018系统正在运行……
Mon Feb 12 18:36:01 CST 2018系统正在运行……
Mon Feb 12 18:36:11 CST 2018系统正在运行……
Mon Feb 12 18:36:21 CST 2018系统正在运行……
Mon Feb 12 18:36:31 CST 2018系统正在运行……
………………………………


如果定时器的起始时间是过去的某个时刻,那么当启动定时器后,会从当前时刻开始算,每隔10s执行一次定时器任务。指定的起始时间是2018-02-12 18:33:00 ,而当前时间是18:35:41 ,因此从18:35:41 时刻开始每隔10s执行一次定时器任务。

2、scheduleAtFixedRate   

public static void main(String[] args) throws ParseException {
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
        Date date = sf.parse("2018-02-12 18:39:00");

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                System.out.println(new Date() + "系统正在运行……");
            }
        }, date, 10*1000);
    }


运行定时器方法,输出结果如下:

Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:10 CST 2018系统正在运行……
Mon Feb 12 18:42:20 CST 2018系统正在运行……
Mon Feb 12 18:42:30 CST 2018系统正在运行……


如果指定的起始时间是过去某个时刻,定时器会迅速执行完从起始时刻到当前时刻要执行的定时器任务次数,然后再每隔10s执行一次定时器任务。 
网上有段解释: 
对于scheduleAtFixedRate,如果指定开始时间是2005/12/30 14:10:00,间隔为3分钟,如果在14:17:00分执行这个程序,会立刻执行3次定时器任务,分别对应14:10:00、14:13:00、14:16:00 时刻应该执行的定时任务,那么第四次执行定时器任务的时间应该是14:19:00,而不是14:20:00 ,就是说是从指定的开始时间开始计时,而不是从执行时间开始计时。 
但是如果用schedule,间隔时间是3分钟,指定开始时间是2005/12/30 14:10:00,那么在14:17:00分执行这个程序,则立即执行程序一次。并且下一次的执行时间是 14:20,而不是从14:10开始算的周期(14:19)。

四、启动定时器源码
启动一个定时器实质是启动一个线程,每创建一个定时器,就需要新建一个线程,用新创建的线程去执行定时器任务。 
当执行Timer timer = new Timer(); 时,执行了Timer的无参构造器

   

public Timer() {
        this("Timer-" + serialNumber());
    }


然后调用了Timer的有参构造器,设置线程的名字,然后启动线程

public Timer(String name) {
        thread.setName(name);
        thread.start();
    }


原文:https://blog.csdn.net/u010502101/article/details/79318380 

猜你喜欢

转载自blog.csdn.net/w592376568/article/details/84235540