Timer和TimerTask类

本文详细介绍了Java中的Timer和TimerTask类,探讨了schedule和scheduleAtFixedRate方法的区别,通过实例代码展示了如何定义定期执行的任务,以及两种方法在首次执行时间和任务执行周期超时情况下的表现差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Timer和TimerTask类可以看做是实现线程的第三种方式。Timer类是Java定时器类,可保证多个线程共享一个Timer类对象而无需进行外部的同步,所以Timer类是线程安全的。

Timer类

Timer实际上是一个线程,定时调度所有的TimerTask类对象。

构造方法

Timer类有多种构造方法,

构造方法参数说明
Timer()创建一个计时器
Timer(boolean isDaemon)创建一个计时器,可以指定其线程作为守护进程运行
Timer(String name)创建一个指定名称的计时器
Timer(String name, boolean isDaemon)创建一个计时器,并赋予其指定名称,同时设置守护进程的方式运行

schedule和scheduleAtFixedRate方法

schedule方法

schedule方法的调用形式有多种,关键的两个参数为,

参数说明
delay延迟执行的毫秒数,即在delay毫秒后第一次执行
period重复执行的时间间隔
/* time为Date类型,在指定时间执行一次*/
timer.schedule(TimerTask task, Date time)

/* firstTime为Date类型,period为long,
 在firstTime时刻第一次执行,之后每隔period毫秒执行一次*/
timer.schedule(TimerTask task, Date firstTime, long period)

/* delay为long类型,从当前开始delay毫秒后执行一次*/
timer.schedule(TimerTask task, long delay)

/* delay为long类型,period为long,
 从当前开始delay毫秒后执行一次,之后每隔period毫秒执行一次*/
timer.schedule(TimerTask task, long delay, long period)

scheduleAtFixedRate方法

scheduleAtFixedRate方法的功能域schedule方法相同,都是定时执行任务,二者之间的区别在之后会说明,该方法的关键参数与schedule方法一样都是delay和period。调用主要有两种形式,

/* 指定的时间第一次执行,之后每隔period毫秒执行一次*/
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

/* 从现在算起delay毫秒之后执行,之后每隔period毫秒执行一次*/
scheduleAtFixedRate(TimerTask task, long delay, long period)

TimerTask类

TimerTask类是一个抽象类,由Timer类安排其第一次执行和重复执行的时间。Timer类有一个抽象方法run方法,该方法内存放定时执行的代码。每个具体的任务类都必须继承TimerTask并重写其run方法。

TimerTask类中存在两个非抽象方法,

方法说明
boolean cancel()取消此任务
long scheduledExecutionTime()返回此任务最近一次执行的时间

实例代码

定义定期被执行的任务类

实现一个TimeTask的子类,

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;

public class MyTimerTask extends TimerTask {
	private String name;
	public MyTimerTask(String name) {
		this.name = name
	}

	@override
	public void run() {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current execute time is: " + sf.format(calendar.getTime()));
		System.out.println("current exec name is: " + this.name);
	}
}

定时任务器

import java.util.Timer;

public class MyTimer {
	public static void main(String[] args) {
		// 创建Timer实例
		Timer timer = new Timer();
		// 创建TimerTask实例
		MyTimerTask myTimerTask = new MyTimerTask("No.1");
		// 两秒后第一次执行,之后每隔一秒执行一次
		timer.schedule(myTimerTask, 2000, 1000);
	}
}

输出结果如下,

current exec time is:2019-07-30 14:35:22
current exec name is:No.1
current exec time is:2019-07-30 14:35:23
current exec name is:No.1
current exec time is:2019-07-30 14:35:24
current exec name is:No.1

schedule与scheduleAtFixedRate方法的区别

方法差异
schedule更注重保持时间间隔的稳定,保证每隔period毫秒可调用一次
scheduleAtFixedRate更注重保持频率的稳定,保证多次调用的频率趋近period毫秒。如果任务执行的间隔大于period时,会立即执行下一次任务。

schedule方法

还是上方的MyTimerTask类的任务为例,

  • 在时间等于或超过time的时候执行,且只执行一次
public class MyTimer {
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
		// 设置Calendar的时间比当前实际时间快3秒
		calendar.add(Calendar.SECOND, 3);
		
		Timer timer = new Timer();
		MyTimerTask myTimerTask = new MyTimerTask("schedule1");
		timer.schedule(myTimerTask, calendar.getTime());
	}
}

返回结果,

current exec time is:2019-07-30 15:46:16
current exec time is:2019-07-30 15:46:19
Current exec name is:schedule1

执行时的时间显示在第一行,三秒钟后任务被执行且仅执行一次。

  • 时间等于或超过 time 的时候首次执行,之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
		// 设置Calendar的时间比当前实际时间快3秒
		calendar.add(Calendar.SECOND, 3);
		
		Timer timer = new Timer();
		MyTimerTask myTimerTask = new MyTimerTask("schedule2");
		timer.schedule(myTimerTask, calendar.getTime(), 3000);
	}
}

返回结果,

current exec time is:2019-07-30 15:54:32
current exec time is:2019-07-30 15:54:35
Current exec name is:schedule2
current exec time is:2019-07-30 15:54:38
Current exec name is:schedule2
current exec time is:2019-07-30 15:54:41
Current exec name is:schedule2

  • 等待 delay 毫秒之后执行且执行一次 task
public class MyTimer {
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
			
		Timer timer = new Timer();
		MyTimerTask myTimerTask = new MyTimerTask("schedule3");
		timer.schedule(myTimerTask, 1000);
	}
}

current exec time is:2019-07-30 16:00:06
current exec time is:2018-06-05 16:00:07
Current exec name is:schedule3

延时了1秒后执行,且执行了一次。

  • 等待 delay 毫秒之后,首次执行,并且之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
			
		Timer timer = new Timer();
		MyTimerTask myTimerTask = new MyTimerTask("schedule4");
		timer.schedule(myTimerTask, 10003000);
	}
}

返回结果,

current exec time is:2019-07-30 16:01:36
current exec time is:2019-07-30 16:01:37
Current exec name is:schedule4
current exec time is:2019-07-30 16:01:40
Current exec name is:schedule4
current exec time is:2019-07-30 16:01:43
Current exec name is:schedule4

延迟一秒后第一次执行,之后每隔3秒执行一次。

scheduleAtFixedRate方法

  • 时间等于或者超过 time 时首次执行 task,之后每隔 period 毫秒重复执行一次
public class MyTimer {
	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
		// 设置Calendar的时间比当前实际时间快3秒
		calendar.add(Calendar.SECOND, 3);
		
		Timer timer = new Timer();
		MyTimerTask myTimerTask = new MyTimerTask("scheduleAtFixedRate1");
		timer.scheduleAtFixedRate(myTimerTask, calendar.getTime(), 3000);
	}
}

返回结果,

current exec time is:2019-07-30 16:11:48
current exec time is:2019-07-30 16:11:51
Current exec name is:scheduleAtFixedRate1
current exec time is:2019-07-30 16:11:54
Current exec name is:scheduleAtFixedRate1
current exec time is:2019-07-30 16:11:57
Current exec name is:scheduleAtFixedRate1

  • 等待 delay 毫秒之后,首次执行,并且之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
   public static void main(String[] args) {
   	Calendar calendar = Calendar.getInstance();
   	SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   	System.out.println("current exec time is:"+ sf.format(calendar.getTime()));
   		
   	Timer timer = new Timer();
   	MyTimerTask myTimerTask = new MyTimerTask("scheduleAtFixedRate2");
   	timer.scheduleAtFixedRate(myTimerTask, 10003000);
   }
}

返回结果

current exec time is:2019-07-30 16:15:47
current exec time is:2019-07-30 16:15:48
Current exec name is:scheduleAtFixedRate2
current exec time is:2019-07-30 16:15:51
Current exec name is:scheduleAtFixedRate2
current exec time is:2019-07-30 16:15:54
Current exec name is:scheduleAtFixedRate2

两种方法差异对比

设定的首次执行时间早于当前时间

  • schedule方法
public class DifferenceTest {
    public static void main(String[] args) {
        // 获取当前时间按照指定的格式输出
        final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        System.out.println("current time is:"+ sf.format(calendar.getTime()));
        
        // Calendar设置成比实际时间的6秒之前
        calendar.add(Calendar.SECOND, -6);
        System.out.println("current time minus six second is :"+ sf.format(calendar.getTime()));
        System.out.println("Task is being executed!");
        
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
            }
        }, calendar.getTime(), 2000);    
    }
}

返回结果,

current time is:2019-07-31 13:09:57
current time minus six second is :2019-07-31 13:09:51
scheduled exec time is :2019-07-31 13:09:57
scheduled exec time is :2018-07-05 13:09:59
scheduled exec time is :2018-07-05 13:10:01
scheduled exec time is :2018-07-05 13:10:03
scheduled exec time is :2019-07-31 13:10:05
scheduled exec time is :2019-07-31 13:10:07
scheduled exec time is :2019-07-31 13:10:09

虽然将时间提前了6秒,但是使用 schedule方法还是从当前时间开始执行。然后每隔两秒执行一次。

  • scheduleAtFixedRate方法
    对上面的代码稍加修改,
timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
            }
        }, calendar.getTime(), 2000);

返回结果,

current time is:2019-07-31 14:32:34
current time minus six second is :2019-07-31 14:32:28
scheduled exec time is :2019-07-31 14:32:28
scheduled exec time is :2019-07-31 14:32:30
scheduled exec time is :2019-07-31 14:32:32
scheduled exec time is :2019-07-31 14:32:34
scheduled exec time is :2019-07-31 14:32:36
scheduled exec time is :2019-07-31 14:32:38

在启动执行的时候,会立马执行3次,就是为了追赶已经过去的6秒。然后再按照设定的间隔,每两秒钟执行一次。

任务执行时间超出执行周期

假设任务执行需要3秒,而定义的执行的周期为2秒。

  • schedule方法
public class DifferenceTest {   
    public static void main(String[] args) {        
        final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        System.out.println("current time is:"+ sf.format(calendar.getTime()));
        
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 模拟当前执行的过程需要 3秒
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
            }
        }, calendar.getTime(), 2000); 
    }
}

返回结果,

current time is:2019-07-31 14:43:51
scheduled exec time is :2019-07-31 14:43:51
scheduled exec time is :2019-07-31 14:43:54
scheduled exec time is :2019-07-31 14:43:57
scheduled exec time is :2019-07-31 14:44:00
scheduled exec time is :2019-07-31 14:44:03

当前的时间为 14:43:51,然后第一次计划执行的时间也为 14:43:51。但是以后每次执行的时间都是相隔 3秒钟,并不是我们上面设置 timerTask 的时间间隔 2秒。所以说使用 schedule 方法,在这种情况下会不断的延后。

  • scheduleAtFixedRate方法
    对上方代码进行修改,
timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
            }
        }, calendar.getTime(), 2000);  
    }

返回结果,

current time is:2019-07-31 10:15:51
scheduled exec time is :2019-07-31 10:15:51
scheduled exec time is :2019-07-31 10:15:53
scheduled exec time is :2019-07-31 10:15:55
scheduled exec time is :2019-07-31 10:15:57
scheduled exec time is :2019-07-31 10:15:59

当执行的频率为2秒钟,但是执行的时间为3秒的时。从控制台上的输出可以看到,执行的频率还是为2秒,因此就会存在并发性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值