学而实习之 不亦乐乎

Java 使用 Timer 和 TimerTask 实现定时任务

2022-09-18 15:04:56

编程中经常会需要执行定时任务,首先想到的是 Timer 定时器来实现。在 java 中一个定时任务由 Timer、TimerTask 两个类来配合完成。

一、Timer 和 TimerTask 简介

Timer:一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。

TimerTask:Timer 安排为一次执行或重复执行的任务。我们可以这样理解Timer是一种定时器工具,用来在一个后台线程计划执行指定任务,而TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。


二、Timer 类

Timer类可以保证多个线程可以共享单个 Timer 对象而无需进行外部同步,所以 Timer 类是线程安全的。但是由于每一个 Timer 对象对应的是单个后台线程,用于顺序执行所有的计时器任务,一般情况下我们的线程任务执行所消耗的时间应该非常短,但是由于特殊情况导致某个定时器任务执行的时间太长,那么他就会“独占”计时器的任务执行线程,其后的所有线程都必须等待它执行完,这就会延迟后续任务的执行,使这些任务堆积在一起。

Timer 的 schedule() 方法如下:
schedule(TimerTask task, Date time):安排在指定的时间执行指定的任务。
schedule(TimerTask task, Date firstTime, long period) :安排指定的任务在指定的时间开始进行重复的固定延迟执行。
schedule(TimerTask task, long delay) :安排在指定延迟后执行指定的任务。
schedule(TimerTask task, long delay, long period) :安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

重载方法 scheduleAtFixedRate() 方法与 schedule() 方法类似。如下:
scheduleAtFixedRate(TimerTask task, Date firstTime, long period):安排指定的任务在指定的时间开始进行重复的固定速率执行。
scheduleAtFixedRate(TimerTask task, long delay, long period):安排指定的任务在指定的延迟后开始进行重复的固定速率执行。


三、TimerTask 类

TimerTask 类是一个抽象类,由 Timer 安排为一次执行或重复执行的任务。它有一个抽象方法 run() 方法,该方法用于执行相应计时器任务要执行的操作。因此每一个具体的任务类都必须继承 TimerTask,然后重写 run() 方法。

它有两个非抽象的方法如下:
boolean cancel():取消此计时器任务。
long scheduledExecutionTime():返回此任务最近实际执行的安排执行时间。


四、实例

1、指定延迟时间执行定时任务

public class TimerTest {

    Timer timer;
    public TimerTest(int time){
        timer = new Timer();
        timer.schedule(new TimerTaskTest(), time * 1000);
    }

    public static void main(String[] args) {
        System.out.println("timer begin....");
        new TimerTest(3);
    }
}

public class TimerTaskTest extends TimerTask{
    public void run() {
        System.out.println("Time's up!!!!");
    }
}

运行结果:

timer begin....
Time's up!!!!

2、在指定时间执行定时任务

public class TimerTest {
    Timer timer;
    public TimerTest(){
        Date time = getTime();
        System.out.println("指定时间time=" + time);
        timer = new Timer();
        timer.schedule(new TimerTaskTest(), time);
    }
    
    public Date getTime(){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 11);

    calendar.set(Calendar.MINUTE, 39);
        calendar.set(Calendar.SECOND, 00);
        Date time = calendar.getTime();
        return time;

    }
    
    public static void main(String[] args) {
        new TimerTest();
    }
}

import java.util.TimerTask;
public class TimerTaskTest extends TimerTask extends TimerTask {

    @Override
    public void run() {
        System.out.println("指定时间执行线程任务...");
    }
}

执行结果为:

指定时间time=Thu Sep 08 14:42:00 CST 2022
指定时间执行线程任务...

3、在延迟指定时间后以指定的间隔时间循环执行定时任务

public class TimerTest {
    Timer timer;
    public TimerTest(){ 
        timer = new Timer();
        timer.schedule(new TimerTaskTest(), 1000, 2000);
    }

    public static void main(String[] args) {
        new TimerTest();
    }
}
    
public class TimerTaskTest extends TimerTask{
    @Override
    public void run() {
        Date date = new Date(this.scheduledExecutionTime());
        System.out.println("本次执行该线程的时间为:" + date);
    }
}

运行结果:

本次执行该线程的时间为:Thu Sep 08 14:44:37 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:39 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:41 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:43 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:45 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:47 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:49 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:51 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:53 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:44:55 CST 2022

.................

对于这个线程任务,如果我们不将该任务停止,他会一直运行下去。


4、在指定的延迟时间后开始以固定速率重复地执行

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
 
public class TimerTest {
 
    /**
     * 延迟100ms后,间隔1s打印出:hello world
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Timer t = new Timer();
        t.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println("本次执行该线程的时间为:" + date);
            }
        }, 100, 1000);
    }
}

结果:

本次执行该线程的时间为:Thu Sep 08 14:32:05 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:06 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:07 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:08 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:09 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:10 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:11 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:12 CST 2022
本次执行该线程的时间为:Thu Sep 08 14:32:13 CST 2022

.................