1.基本简介

java.util.TimerTask:表示一个定时任务
基本使用:

TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
            }
        };

java.util.Timer:定时器,主要负责定时任务的调度和执行
核心方法介绍

//单次执行:当前时间延迟:delay毫秒后运行task
public void schedule(TimerTask task, long delay);
//单次执行:在绝对时间 time的时候执行task
public void schedule(TimerTask task, Date time);


//固定延迟重复执行:第一次的执行时间是当前时间+delay
public void schedule(TimerTask task, long delay, long period);

//固定延迟重复执行:第一次执行时间是:firstTime
//后一次的执行时间是前一次的实际执行时间+period
public void schedule(TimerTask task, Date firstTime, long period);

//固定频率重复执行:第一次执行时间是:firstTime
//后一次的执行时间是前一次的实际执行时间+period
public void scheduleAtFixedRate(TimerTask task, long delay, long period);
//固定频率重复执行:第一次的执行时间是当前时间+delay
public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period);

简单说明
(1)对于固定延时,它是基于上次任务的“实际”执行时间来算的,如果因为某些原因,上次任务延时了,则本次任务也会延时,而固定频率会尽量补够运行次数。
(2)如果第一个执行计划的时间:firstTime是一个过去时间,就会立即执行。
基本原理
(1)Timer内部是有任务队列和Timer线程组成。

private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);

(2)任务队列是按照下次的执行时间来优先排序的。
(3)一个Timer对象只有一个Timer线程,所以当一个Timer对象执行多个TimerTask任务时,会出现堵塞的现象。

2.情景一:普通的使用

(1)使用TimerTask定义任务
(2)Timer 的 schedule方法进行任务的调度

import java.util.Timer;
import java.util.TimerTask;

public class Test {
    public static void main(String[] args) {
        
        TimerTask task=new TimerTask() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务:"+System.currentTimeMillis()+"]");
            }
        };

        Timer timer=new Timer();
        timer.schedule(task,100,3000);

    }
}

效果:可发现是单线程的,一直用的是Timer-0线程

JAVA py 后端定时任务 java定时任务时间_java

3.情景二:一个Timer执行多个Task,堵塞现象

(1)定义了两个TimerTask,其中一个TimerTask中使用线程睡眠10秒

TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
            }
        };
        
        TimerTask task2=new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
            }
        };


        Timer timer=new Timer();
        timer.schedule(task2,1000);
        timer.schedule(task1,100,3000);

效果:会堵塞10秒,然后再继续执行Task1的循环定时任务,看源码可知,Timer执行任务时单线程

JAVA py 后端定时任务 java定时任务时间_JAVA py 后端定时任务_02

4.情景三:出现异常的情况

强调:在执行任何一个任务的run方法时,一旦run抛出了异常,Timer线程就会退出,从而所有定时任务都会被取消。如果希望各个定时任务互不干扰,一定要在run方法内捕获所有异常。

TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
            }
        };

        TimerTask task2=new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
                throw new RuntimeException("抛出个异常玩玩");
            }
        };


        Timer timer=new Timer();

        timer.schedule(task1,100,3000);
        timer.schedule(task2,1000);

现象:

JAVA py 后端定时任务 java定时任务时间_定时任务_03


搞两个Timer去分别跑任务,并不会影响

TimerTask task1=new TimerTask() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
            }
        };

        TimerTask task2=new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String name = Thread.currentThread().getName();
                System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
                throw new RuntimeException("抛出个异常玩玩");
            }
        };
        
        Timer timer1=new Timer();
        Timer timer2=new Timer();
        
        timer1.schedule(task1,100,3000);
        timer2.schedule(task2,1000);

现象:

JAVA py 后端定时任务 java定时任务时间_并发编程_04