java.util.Timer简介以及简单使用示例

一、简介

定时器(Timer)是一个工具类,用于安排任务(java.util.TimerTask)在指定时间后执行或以指定的时间间隔重复执行。它可以用于执行定时任务、定时调度和时间延迟等操作。

定时器(Timer)可以应用于许多场景,比如:

调度任务(固定速率):当你需要按照预定时间执行任务时,可以使用定时器。例如,每天凌晨执行数据备份、定时生成报表、定时发送通知等。即scheduleAtFixedRate的2个重载方法。

超时处理(固定延迟):当你需要处理某个操作的超时情况时,可以使用定时器。例如,设置一个操作的超时时间,如果在规定时间内未完成,则执行相应的超时处理逻辑。即schedule的4个重载方法。

Java中的定时器:java.util.Timer,它的常用方法:

Java 8 中文版 - 在线API手册 - 码工具

Modifier and Type

Method and Description

参数说明

void

cancel()

终止此计时器,丢弃任何当前计划的任务。

/

int

purge()

从该计时器的任务队列中删除所有取消的任务。

/

void

schedule(TimerTask task, Date time)

在指定的时间安排指定的任务执行。如果此时间已过去,则安排立即执行该任务

task:要调度的任务

time:执行任务的时间

void

schedule(TimerTask task, Date firstTime, long period)

从指定 的时间开始 ,对指定的任务执行重复的 固定延迟执行 。

task:要调度的任务

firstTime:第一次执行任务的时间

period:连续任务以毫秒为单位的时间间隔

void

schedule(TimerTask task, long delay)

在指定的延迟之后安排指定的任务执行。

task:要调度的任务

delay:在执行任务之前,以毫秒为单位进行延迟的时间

void

schedule(TimerTask task, long delay, long period)

在指定 的延迟之后开始 ,重新执行 固定延迟执行的指定任务。

task:要调度的任务

delay:在执行任务之前,以毫秒为单位进行延迟的时间

period:连续任务以毫秒为单位的时间间隔

void

scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

从指定的时间 开始 ,对指定的任务执行重复的 固定速率执行 。

task:要调度的任务

firstTime:第一次执行任务的时间

period:连续任务以毫秒为单位的时间间隔

void

scheduleAtFixedRate(TimerTask task, long delay, long period)

在指定的延迟之后 开始 ,重新执行 固定速率的指定任务。

task:要调度的任务

delay:在执行任务之前,以毫秒为单位进行延迟的时间

period:连续任务以毫秒为单位的时间间隔

二、schedule和scheduleAtFixedRate方法的区别

这两个方法都是任务调度方法,他们之间区别是,schedule会保证任务的间隔是按照定义的period参数严格执行的,如果某一次调度时间比较长,那么后面的时间会顺延,保证调度间隔都是period,而scheduleAtFixedRate是严格按照调度时间来的,如果某次调度时间太长了,那么会通过缩短间隔的方式保证下一次调度在预定时间执行。举个栗子:你每个3秒调度一次,那么正常就是0,3,6,9s这样的时间,如果第二次调度花了2s的时间,如果是schedule,就会变成0,3+2,8,11这样的时间,保证间隔,而scheduleAtFixedRate就会变成0,3+2,6,9,压缩间隔,保证调度时间。

三、定时器(Timer)使用步骤

我们要实现一个定时任务,只需要实现TimerTask的run方法即可。每一个任务都有下一次执行时间nextExecutionTime(毫秒),如果是周期性的任务,那么每次执行都会更新这个时间为下一次的执行时间,当nextExecutionTime小于当前时间时,都会执行它。

(1)第一步:创建一个Timer。

(2)第二步:创建一个TimerTask。

(3)第三步:使用Timer执行TimerTask。

其中第三步无疑是我们目前最关心的,也就是timer.schedule(myTask, 2000L, 1000L)。他的意思是myTask在两秒钟之后开始第一次执行,然后每隔一秒执行一次。这只是最基本的用法。就体现了Timer定时执行的流程。

示例1:超时处理(固定延迟)

在2秒后开始执行,只执行一次

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimeTest {
    public static void main(String[] args) {
        System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));

        Timer timer = new Timer();  // (1)第一步:创建一个Timer。
        timer.schedule(new TimerTask() {  // (2)第二步:创建一个TimerTask。(3)第三步:使用Timer执行TimerTask。
            @Override
            public void run() {
                System.out.println("Timer is running");
                System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
            }
        }, 2000);
    }
}

运行结果:

当前时间:2023-08-19 22-45-46:161

Timer is running

当前时间:2023-08-19 22-45-48:169

示例2:调度任务(固定速率)

执行周期性任务,只需要添加schedule的第三个参数period。

在2秒后开始执行,每隔1秒执行一次

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimeTest {
    public static void main(String[] args) {
        System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));

        Timer timer = new Timer(); // (1)第一步:创建一个Timer。
        timer.schedule(new TimerTask() { // (2)第二步:创建一个TimerTask。(3)第三步:使用Timer执行TimerTask。
            @Override
            public void run() {
                System.out.println("Timer is running");
                System.out.println("当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
            }
        }, 2000, 1000);
    }
}

运行结果:

当前时间:2023-08-19 22-48-10:190

Timer is running

当前时间:2023-08-19 22-48-12:200

Timer is running

当前时间:2023-08-19 22-48-13:203

Timer is running

当前时间:2023-08-19 22-48-14:216

示例32个Timer实例调度任务(固定速率)

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimeTest {
    public static void main(String[] args) {
        System.out.println("timer当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
        Timer timer = new Timer(); // (1)第一步:创建一个Timer。
        timer.schedule(new TimerTask() { // (2)第二步:创建一个TimerTask。(3)第三步:使用Timer执行TimerTask。
            @Override
            public void run() {
                System.out.println("Timer is running");
                System.out.println("timer当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
            }
        }, 2000, 1000);

        System.out.println("timer2当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
        Timer timer2 = new Timer(); // (1)第一步:创建一个Timer。
        timer2.schedule(new TimerTask() { // (2)第二步:创建一个TimerTask。(3)第三步:使用Timer执行TimerTask。
            @Override
            public void run() {
                System.out.println("Timer2 is running");
                System.out.println("timer2当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss:SSS").format(new Date()));
            }
        }, 3000, 2000);
    }
}

运行结果:

timer当前时间:2023-08-20 00-08-06:746

timer2当前时间:2023-08-20 00-08-06:748

Timer is running

timer当前时间:2023-08-20 00-08-08:750

Timer is running

Timer2 is running

timer2当前时间:2023-08-20 00-08-09:755

timer当前时间:2023-08-20 00-08-09:755

Timer is running

timer当前时间:2023-08-20 00-08-10:769

Timer2 is running

timer2当前时间:2023-08-20 00-08-11:768

Timer is running

timer当前时间:2023-08-20 00-08-11:784

Timer is running

timer当前时间:2023-08-20 00-08-12:787

Timer2 is running

timer2当前时间:2023-08-20 00-08-13:770

四、Timer的缺陷

1、由于执行任务的线程只有一个,所以如果某个任务的执行时间过长,那么将破坏其他任务的定时精确性。如一个任务每1秒执行一次,而另一个任务执行一次需要5秒,那么如果是固定速率的任务,那么会在5秒这个任务执行完成后连续执行5次,而固定延迟的任务将丢失4次执行。

2、如果执行某个任务过程中抛出了异常,那么执行线程将会终止,导致Timer中的其他任务也不能再执行。

3、Timer使用的是绝对时间,即是某个时间点,所以它执行依赖系统的时间,如果系统时间修改了的话,将导致任务可能不会被执行。

五、更好的替代方法

由于Timer存在上面说的这些缺陷,在JDK1.5中,我们可以使用ScheduledThreadPoolExecutor来代替它,使用Executors.newScheduledThreadPool工厂方法或使用ScheduledThreadPoolExecutor的构造函数来创建定时任务,它是基于线程池的实现,不会存在Timer存在的上述问题,当线程数量为1时,它相当于Timer。

猜你喜欢

转载自blog.csdn.net/xijinno1/article/details/132386799