定时器 Timer

239 阅读5分钟

1. Timer 和 TimerTask

  • Timer:设置计划任务
  • TimerTask:任务的实现

2. schedule(TimerTask task, Date time) 方法

指定日期执行一次定时任务

2.1 晚于当前时间执行任务

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer();
        timer.schedule(getTimerTask(), planDate);
        
        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task run date=" + new Date());
            }
        };
    }
}

2.2 早于当前时间执行任务,则立即执行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - 10);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("task planDate=" + planDate);

        Timer timer = new Timer();
        timer.schedule(getTimerTask(), planDate);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task run date=" + new Date());
            }
        };
    }
}

2.3 多个任务执行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date planDate1 = calendar.getTime();
        calendar.add(Calendar.SECOND, 5);
        Date planDate2 = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("task1 planDate1=" + planDate1);
        System.out.println("task2 planDate2=" + planDate2);

        Timer timer = new Timer();
        timer.schedule(getTimerTask1(), planDate1);
        timer.schedule(getTimerTask2(), planDate2);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask1() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task1 run date=" + new Date());
            }
        };
    }

    private static TimerTask getTimerTask2() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task2 run date=" + new Date());
            }
        };
    }
}

2.4 多个任务时的延迟执行

TimerTask 任务是以队列的方式一个一个被顺序执行的,所以任务实际执行的时间可能和计划的不一致,因为前面的任务可能执行的时间过长,导致后面的任务的执行被延迟了

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date planDate1 = calendar.getTime();
        calendar.add(Calendar.SECOND, 5);
        Date planDate2 = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("task1 planDate1=" + planDate1);
        System.out.println("task2 planDate2=" + planDate2);

        Timer timer = new Timer();
        timer.schedule(getTimerTask1(), planDate1);
        timer.schedule(getTimerTask2(), planDate2);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask1() {
        return new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("task1 run begin date=" + new Date());
                    Thread.sleep(20000);
                    System.out.println("task1 run end date=" + new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
    }

    private static TimerTask getTimerTask2() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task2 run begin date=" + new Date());
                System.out.println("task2 run end date=" + new Date());
            }
        };
    }
}

2.5 进程未销毁?

  • 可以发现,上面的自动任务执行完后进程未销毁,因为创建一个 Timer 就是启动一个新的线程,这个线程默认情况下不是守护线程,所以它一直在运行

  • Timer 可以设置以守护线程的方式运行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer(true);
        timer.schedule(getTimerTask(), planDate);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task run Date=" + new Date());
            }
        };
    }
}

上面的代码执行后,打印了"main end"后进程销毁了,未执行 TimerTask 任务。因为 main 主线程执行完毕后销毁了,Timer 作为守护线程也跟着一起销毁了

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

指定日期后,再按指定间隔时间(period)周期性无限循环执行任务

3.1 晚于当前时间执行任务

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 5);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer();
        timer.schedule(getTimerTask(), planDate, 3000);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task run date=" + new Date());
            }
        };
    }
}

3.2 早于当前时间执行任务,则立即执行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - 10);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer();
        timer.schedule(getTimerTask(), planDate, 3000);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                System.out.println("task run date=" + new Date());
            }
        };
    }
}

3.3 延迟执行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 5);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer();
        timer.schedule(getTimerTask(), planDate, 3000);

        System.out.println("main end");
    }

    private static TimerTask getTimerTask() {
        return new TimerTask() {
            @Override
            public void run() {
                try {
                    System.out.println("task run begin date=" + new Date());
                    Thread.sleep(4000);
                    System.out.println("task run end date=" + new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };
    }
}

4. cancel() 方法

4.1 TimerTask 类的 cancel() 方法

TimerTask 类的 cancel() 方法是将自身从任务列表中清除

public class Test {

    public static void main(String[] args) {
        Date currentDate = new Date();
        System.out.println("currentDate=" + currentDate);

        Timer timer = new Timer();
        timer.schedule(new TimerTaskA(), currentDate, 2000);
        timer.schedule(new TimerTaskB(), currentDate, 3000);

        System.out.println("main end");
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run date=" + new Date());
            this.cancel();
        }
    }

    static class TimerTaskB extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskB run date=" + new Date());
        }
    }
}

4.2 Timer 类的 cancel() 方法

Timer 类的 cancel() 方法是将任务队列中所有任务清除

public class Test {

    public static void main(String[] args) throws InterruptedException {
        Date currentDate = new Date();
        System.out.println("currentDate=" + currentDate);

        Timer timer = new Timer();
        timer.schedule(new TimerTaskA(), currentDate, 2000);
        timer.schedule(new TimerTaskB(), currentDate, 3000);

        Thread.sleep(10000);
        timer.cancel();
        
        System.out.println("main end");
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run date=" + new Date());
        }
    }

    static class TimerTaskB extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskB run date=" + new Date());
        }
    }
}

4.3 Timer 类的 cancel() 方法注意事项

Timer 类的 cancel() 方法有时并不一定会停止执行任务,因为 Timer 类的 cancel() 方法有时没有争抢到 queue 锁

public class Test {

    private static int i = 1;

    public static void main(String[] args) {
        while (true) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.SECOND, 3);
            Timer timer = new Timer();
            timer.schedule(new TimerTaskA(), calendar.getTime());
            timer.cancel();
            i++;
        }
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run i=" + i);
            this.cancel();
        }
    }
}

5. schedule(TimerTask task, long delay) 方法

以执行该方法时的时间为参考时间,在此基础上延迟指定毫秒数(delay)后执行一次 TimerTask 任务

public class Test {

    public static void main(String[] args) {
        System.out.println("currentTime=" + new Date());
        Timer timer = new Timer();
        timer.schedule(new TimerTaskA(), 2000);

        System.out.println("main end");
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run date=" + new Date());
        }
    }
}

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

以执行该方法时的时间为参考时间,在此基础上延迟指定毫秒数(delay)后,再以间隔时间(period)周期性无限循环执行任务

public class Test {

    public static void main(String[] args) {
        System.out.println("currentTime=" + new Date());
        Timer timer = new Timer();
        timer.schedule(new TimerTaskA(), 2000, 5000);

        System.out.println("main end");
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run date=" + new Date());
        }
    }
}

7. scheduleAtFixedRate() 方法的追赶性

scheduleAtFixedRate() 方法具有追赶性。如果是早于当前时间执行任务的情况下,调用该方法会将这段提前时间段内对应的任务”补充“地执行

public class Test {

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - 20);
        Date planDate = calendar.getTime();

        System.out.println("currentDate=" + new Date());
        System.out.println("planDate=" + planDate);

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTaskA(), planDate, 2000);

        System.out.println("main end");
    }

    static class TimerTaskA extends TimerTask {
        @Override
        public void run() {
            System.out.println("taskA run date=" + new Date());
        }
    }
}

学自《Java多线程编程核心技术》