定时器的实现原理就是新开一个子线程执行定时任务。

一、一次执行定时器。

一次执行定时器的时间如果在当前时间以前会立即执行任务,如果在未来时间,则会到指定的未来时间再执行任务。

示例代码:

public static void main(String[] args) {
    try{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date dateRef = sdf.parse("2017-06-08 15:00:00");
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("我执行了,时间:" + new Date());
            }
        }, dateRef);;
    } catch(ParseException e) {
        e.printStackTrace();
    }
}

输出结果:

我执行了,时间:Thu Jun 08 20:37:29 CST 2017

执行完后程序并不会停止,因为是新开的一个线程,新线程不是守护线程,所有主线程执行完毕子线程不会停止,要想让定时器执行完任务后立即停止,可以查看Timer类的构造方法:

// 无参构造
public Timer() {
    this("Timer-" + serialNumber());
}
// 设置子线程是否为守护线程
public Timer(boolean isDaemon) {
    this("Timer-" + serialNumber(), isDaemon);
}
// 给子线程起一个名字
public Timer(String name) {
    thread.setName(name);
    thread.start();
}

我们可以通过Timer(true)创建Timer对象设置子线程为守护线程,在任务执行完毕子线程立即退出。

二、无限次执行定时器

示例代码:

public static void main(String[] args) {
    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("当前时间:" + new Date());
        }
    }, new Date(), 3000);

    // 默认从当前时间开始,以 period 间隔时间无限次数执行某一任务
    // new Timer().schedule(TimerTask task, long period);

    // 以当前时间为参考时间,在此基础上延迟 delay 毫秒数,再以 period 间隔时间无限次数执行某一任务
    // new Timer().schedule(TimerTask task, long delay, long period);
}

输出结果:

当前时间:Thu Jun 08 20:43:12 CST 2017
当前时间:Thu Jun 08 20:43:15 CST 2017
当前时间:Thu Jun 08 20:43:18 CST 2017
当前时间:Thu Jun 08 20:43:21 CST 2017

程序还在每隔3秒的执行一次并没有停止。

schedule方法的下一次执行任务的时间是从上一次的开始时间算起的,如果我们想从上一次的任务结束时间开始算起可以使用scheduleAtFixedRate方法,除了这一点外,schedule和scheduleAtFixedRate几乎没有其他区别。

定时器的执行是在一个队列内,如果队列前面一个任务的执行任务是很耗时的,可能导致后一个任务的执行并不是在指定的时间点执行,会被延后执行。

定时器也可以将自身从队列内移除,调用TimerTask类的cancel()方法可将自身从任务队列内移除,其他任务不受影响。当然cancel()方法有时候是不起作用的,只有当调用者TimerTask对象获取了任务队列queue的对象锁时才会真正的把自身从任务队列内移除。