java时间调度_深入理解Java定时调度(Timer)机制

简介

在实现定时调度功能的时候,我们往往会借助于第三方类库来完成,比如: quartz 、 Spring Schedule 等等。JDK从1.3版本开始,就提供了基于 Timer 的定时调度功能。在 Timer 中,任务的执行是串行的。这种特性在保证了线程安全的情况下,往往带来了一些严重的副作用,比如任务间相互影响、任务执行效率低下等问题。为了解决 Timer 的这些问题,JDK从1.5版本开始,提供了基于 ScheduledExecutorService 的定时调度功能。

本节我们主要分析 Timer 的功能。对于 ScheduledExecutorService 的功能,我们将新开一篇文章来讲解。

如何使用

Timer 需要和 TimerTask 配合使用,才能完成调度功能。 Timer 表示调度器, TimerTask 表示调度器执行的任务。任务的调度分为两种:一次性调度和循环调度。下面,我们通过一些例子来了解他们是如何使用的。

1. 一次性调度

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

@Override public void run() {

SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

System.out.println(format.format(scheduledExecutionTime()) + ", called");

}

};

// 延迟一秒,打印一次

// 打印结果如下:10:58:24, called

timer.schedule(task, 1000);

}

2. 循环调度 - schedule()

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

@Override public void run() {

SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

System.out.println(format.format(scheduledExecutionTime()) + ", called");

}

};

// 固定时间的调度方式,延迟一秒,之后每隔一秒打印一次

// 打印结果如下:

// 11:03:55, called

// 11:03:56, called

// 11:03:57, called

// 11:03:58, called

// 11:03:59, called

// ...

timer.schedule(task, 1000, 1000);

}

3. 循环调度 - scheduleAtFixedRate()

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

@Override public void run() {

SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

System.out.println(format.format(scheduledExecutionTime()) + ", called");

}

};

// 固定速率的调度方式,延迟一秒,之后每隔一秒打印一次

// 打印结果如下:

// 11:08:43, called

// 11:08:44, called

// 11:08:45, called

// 11:08:46, called

// 11:08:47, called

// ...

timer.scheduleAtFixedRate(task, 1000, 1000);

}

4. schedule()和scheduleAtFixedRate()的区别

从2和3的结果来看,他们达到的效果似乎是一样的。既然效果一样,JDK为啥要实现为两个方法呢?他们应该有不一样的地方!

在正常的情况下,他们的效果是一模一样的。而在异常的情况下 - 任务执行的时间比间隔的时间更长,他们是效果是不一样的。

schedule() 方法,任务的 下一次执行时间 是相对于 上一次实际执行完成的时间点 ,因此执行时间会不断延后

scheduleAtFixedRate() 方法,任务的 下一次执行时间 是相对于 上一次开始执行的时间点 ,因此执行时间不会延后

由于 Timer 内部是通过单线程方式实现的,所以这两种方式都不存在线程安全的问题

我们先来看看 schedule() 的异常效果:

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

@Override public void run() {

SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(format.format(scheduledExecutionTime()) + ", called");

}

};

timer.schedule(task, 1000, 2000);

// 执行结果如下:

// 11:18:56, called

// 11:18:59, called

// 11:19:02, called

// 11:19:05, called

// 11:19:08, called

// 11:19:11, called

}

接下来我们看看 scheduleAtFixedRate() 的异常效果:

public static void main(String[] args) {

Timer timer = new Timer();

TimerTask task = new TimerTask() {

@Override public void run() {

SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(format.format(scheduledExecutionTime()) + ", called");

}

};

timer.scheduleAtFixedRate(task, 1000, 2000);

// 执行结果如下:

// 11:20:45, called

// 11:20:47, called

// 11:20:49, called</

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值