您的位置:首页 > 编程语言 > Java开发

任务调度——java.util.Timer

2015-02-28 17:35 363 查看
在web应用中,多数应用都具有任务调度的功能,也就是在指定时间点,指定时间间隔、指定执行次数下自动执行的任务。任务调度的实现方式有多种:

Timer
ScheduledExecutor
Quartaz
JCronTab

当然,这些实现方式都各有优势,或操作简单,或适用于复杂情况。

Timer是最简单的一种实现任务调度的方法,是JDK自带的类。使用比较简单,需要Timer和TimerTask两个类即可,提供的方法个数少,使用简单。

Timer类负责设定TimerTask的起始和间隔执行时间。具体的执行任务,由用户创建一个TimerTask的继承类,并实现其run()方法。run()就是定时执行的任务:例如:固定时间发送邮件、每隔多长时间发送邮件、每隔多长时间查询某些数据等等。

一、代码抽象

public class TimerTest extends TimerTask
{
    private String jobName = "";
    public TimerTest (String jobName){
        this.jobName = jobName;
    }

    @Override
    public void run()
    {
        System.out.println("execute"+jobName+"执行时间:"+new Date());
    }
}
public static void main( String[] args )
    {
        Timer timer = new Timer();
        long deplay1 = 2 * 1000;
        long period1 = 2000;
        //设置任务立即执行
        timer.schedule( new TimerTest( "job1" ), new Date() );
        //job2延迟2s执行
        timer.schedule( new TimerTest( "job2" ), deplay1 );
        //job3立即执行,并且每隔1s就执行一次
        timer.schedule( new TimerTest( "job3" ), new Date(), deplay1 );
        //job4延迟2s执行,并且每隔2s就执行一次
        timer.schedule( new TimerTest( "job4" ), deplay1, period1 );
        //job5立即执行,并且每隔2s后执行一次
        timer.scheduleAtFixedRate( new TimerTest( "job5" ), new Date(), period1 );
        //job6延迟2s执行,并且每隔2s后执行一次
        timer.scheduleAtFixedRate( new TimerTest( "job6" ), deplay1, period1 );
    }

Timer 的设计核心是一个 TaskList 和一个 TaskThread。Timer 将接收到的任务丢到自己的 TaskList 中,TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。

Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。

二、方法详解

使用Timer调度的任务,主要分为两种方式:

1. 任务在指定时间被执行一次,直到任务被cancel。

//job1立即执行 
timer.schedule( new TimerTest( "job1" ), new Date() ); 
//job2延迟2s执行 
timer.schedule( new TimerTest( "job2" ), 2000 );  
//job3从2015年2月28日执行  如果系统启动时间晚于设定的时间,那系统启动后会立即执行job3
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse( "2015-3-5 10:50:00" );
timer.schedule( new TimerTest( "job3" ), d );
2. 从某一指定时间开始,周期性的执行任务

//job4立即执行,并且每隔2s就执行一次 
timer.schedule( new TimerTest( "job4" ), new Date(), 2000 );
//job5延迟2s执行,并且每隔2s就执行一次
timer.schedule( new TimerTest( "job5" ), 2000, 2000); 
//job6立即执行,并且每隔2s后就执行一次
timer.scheduleAtFixedRate( new TimerTest( "job6" ), new Date(), 2000 );
//job7延迟2s执行,并且每隔2s就执行一次
timer.scheduleAtFixedRate( new TimerTest( "job7" ), 2000, 2000 );
上面四个方法,都是循环执行任务,但是,他们采用的是良好总不同的循环策略。换句话说,也就是我们在讨论schedule()和scheduleAtFixedRate()两者之间的区别。

schedule()的间隔时间,为相对时间法,是指按照上一次执行任务的时间为依据,计算本次执行时间。

例如:第一次执行时间为10:30:00,间隔周期为2s,因系统繁忙(垃圾回收、虚拟内存切换等),10:30:02没有机会执行,知道10:30:03才开始执行第二次任务,那么,第三次执行时间将会是10:30:05,向后顺延了1s。

这种方式,更注重时间间隔的稳定性。举几个使用场景,帮助理解。例如:用Timer控制光标的闪烁时间,如果采用下面介绍的绝对时间策略,那么,当系统从繁忙中恢复后,光标会快速连续闪烁多次,以弥补回在系统繁忙期间没有被执行的任务。

scheduleAtFixedRate()的时间间隔,为绝对时间法。例如上面的例子,虽然第二次任务执行延迟了1s,但是,第三次执行仍然按照正点(10:30:04)执行。这种方式,更注重任务被执行的次数。例如,要求在10s内每s执行一次操作,在第10s结束任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: