Java的定时/计划功能功能
image.png
image.png

定时器Timer相关类的使用

  • Timer类
    设置计划任务,在指定时间开始执行某一任务
  • TimerTask抽象abstract类
    封装任务
  • TimerTask的子类
    执行具体执行任务

Timer相关API

image.png

void schedule(TimerTask task, Date time)

在指定时间执行一次任务,如果设置的时间已经超过则立即执行

//定时器
class AB{
    public static void main(String[] args) throws InterruptedException {
        long now = System.currentTimeMillis();
        System.out.println("当前时间为:"+now);
        long start = now + 1000;
        System.out.println("计划开始时间为:"+start);
        Timer timer = new Timer();
        Thread.sleep(100);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("已经执行任务,时间为:" + System.currentTimeMillis());
            }
        };
        timer.schedule(timerTask,new Date(start));
        System.out.println("main线程走完时间为:"+System.currentTimeMillis());
    }
}

timer对象是执行定时任务
timerTask抽象类实现了Runable接口,其子类是执行具体的代码逻辑,重写run方法的
执行结果如下图
image.png
注意:此时main方法走完之后,定时线程因为不是守护线程还在继续走下去。但是定时任务走完之后线程并没有结束,还在运行

private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");

        // Constrain value of period sufficiently to prevent numeric
        // overflow while still being effectively infinitely large.
        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
            period >>= 1;

        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");

            synchronized(task.lock) {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }

            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }

执行schedule方法的时候将TimerTask加入queue的队列中
image.png
然后一直true死循环查找队列,如果队列为空则释放锁,但是死循环还是一直执行。所以线程不销毁

void cancel()销毁Timer线程

一定要注意虽然可以在run方法内部或者主线程使用,但是一定要确保调用此方法时是最后一条任务结束了,否则所有后续的定时任务都会失效
image.png

执行时间花费过长,影响接下来执行的时间

class AD{
    public static void main(String[] args) throws InterruptedException {
        long now = System.currentTimeMillis();
        System.out.println("当前时间为:"+now);
        long start = now + 1000;
        System.out.println("计划1开始时间为:"+start);
        long start2 = now + 2000;
        System.out.println("计划2开始时间为:" + start2);
        Timer timer = new Timer();
        Thread.sleep(100);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("已经执行1任务,时间为:" + System.currentTimeMillis());
                try {
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("执行1任务完毕,时间为:" + System.currentTimeMillis());
            }
        };
        TimerTask timerTask2 = new TimerTask() {
            @Override
            public void run() {
                System.out.println("已经执行2任务,时间为:" + System.currentTimeMillis());
            }
        };
        timer.schedule(timerTask,new Date(start));
        timer.schedule(timerTask2,new Date(start2));
//        Thread.sleep(2000);
//        timer.cancel();
        System.out.println("main线程走完时间为:"+System.currentTimeMillis());
    }
}

因为只有1个线程去执行,所以被阻塞了
image.png

void scheduleAtFixedRate(TimerTask task, Date firstTime,long period) 在指定日期之后重复周期执行该任务,如果起始时间在以前则立即执行

image.png

Timer和TimerTask的cancel()方法

TimerTask类的cancel方法是取消自身在队列queue的任务
Timer类的cancel方法是取消所有queue的任务
但不是会立即取消任务,有时候会没有抢到queue队列的锁,导致线程继续执行

class AH extends TimerTask {
    private int i;
    public AH(int i) {
        this.i = i;
    }
    @Override
    public void run() {
        System.out.println("第" + i + "次没有被cancel取消");
    }
}
class AG {
    public static void main(String[] args) {
        int i = 0;
        long now = System.currentTimeMillis();
        System.out.println("当前时间为:" + now);
        System.out.println("计划时间为:" + now);
        while (true) {
            i++;
            Timer timer = new Timer();
            AH ah = new AH(i);
            timer.schedule(ah, new Date(now));
            timer.cancel();
        }
    }
}

还是有没有抢到锁,继续执行的现象
image.png

schedule(TimerTask task,long delay,long period)定时间隔执行任务

不具有追赶的特性,从上一个任务结束的时间到下一个任务开始的时间
image.png
image.png

void scheduleAtFixedRate(TimerTask task, long delay, long period) 具有追赶的特性

具有追赶的特性,从上一个任务结束开始的时间到下一个任务开始的时间
例如Spring的@Schedule注解每个整点进行一次任务,其实用的底层是Excuter并发框架的定时
image.png


这个家伙很懒,啥也没有留下😋