1、Timer
Timer myTimer = new Timer();
myTimer.schedule(new Worker(), 1000);//1秒后執(zhí)行
// 2012-02-28 09:58:00執(zhí)行
myTimer.schedule(new Worker(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-02-28 09:58:00"));
myTimer.schedule(new Worker(), 5000,1000);//5秒后執(zhí)行 每一秒執(zhí)行一次
// 2012-02-28 09:58:00執(zhí)行一次 以后每秒執(zhí)行一次,如果設(shè)定的時(shí)間點(diǎn)在當(dāng)前時(shí)間之前,任務(wù)會被馬上執(zhí)行,然后開始按照設(shè)定的周期定時(shí)執(zhí)行任務(wù)
myTimer.schedule(new Worker(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-02-28 09:58:00"),1000);
myTimer.scheduleAtFixedRate(new Worker(), 5000,1000);//5秒后執(zhí)行 每一秒執(zhí)行一次 如果該任務(wù)因?yàn)槟承┰颍ɡ缋占┒舆t執(zhí)行,那么接下來的任務(wù)會盡可能的快速執(zhí)行,以趕上特定的時(shí)間點(diǎn)
myTimer.scheduleAtFixedRate(new Worker(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-02-28 09:58:00"),1000);//和上個(gè)類似
timer的缺點(diǎn):
(1)Timer對調(diào)度的支持是基于絕對時(shí)間,而不是相對時(shí)間的,由此任務(wù)對系統(tǒng)時(shí)鐘的改變是敏感的;
(2)所有的TimerTask只有一個(gè)線程TimerThread來執(zhí)行,因此同一時(shí)刻只有一個(gè)TimerTask在執(zhí)行;
(3)Timer線程并不捕獲異常,所以任何一個(gè)TimerTask的執(zhí)行異常都會導(dǎo)致Timer終止所有任務(wù);這種情況下,Timer也不會再重新恢復(fù)線程的執(zhí)行了;它錯(cuò)誤的認(rèn)為整個(gè)Timer都被取消了。此時(shí),已經(jīng)被安排但尚未執(zhí)行的TimerTask永遠(yuǎn)不會再執(zhí)行了,新的任務(wù)也不能被調(diào)度了。
因此你應(yīng)該考慮使用ScheduledThreadPoolExecutor作為代替品,ScheduledThreadExecutor只支持相對時(shí)間。
2、ScheduleExecutorService
ScheduleExecutorService接口中有四個(gè)重要的方法,其中scheduleAtFixedRate和scheduleWithFixedDelay在實(shí)現(xiàn)定時(shí)程序時(shí)比較方便。
(1)scheduleAtFixedRate
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
command:執(zhí)行線程
initialDelay:初始化延時(shí)
period:兩次開始執(zhí)行最小間隔時(shí)間
unit:計(jì)時(shí)單位
(2)scheduleWithFixedDelay
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
command:執(zhí)行線程
initialDelay:初始化延時(shí)
period:前一次執(zhí)行結(jié)束到下一次執(zhí)行開始的間隔時(shí)間(間隔執(zhí)行延遲時(shí)間)
unit:計(jì)時(shí)單位
(3)功能示例
1.按指定頻率周期執(zhí)行某個(gè)任務(wù)。
初始化延遲0ms開始執(zhí)行,每隔100ms重新執(zhí)行一次任務(wù)。
/**
* 以固定周期頻率執(zhí)行任務(wù)
*/
public static void executeFixedRate() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(
new EchoServer(),
0,
100,
TimeUnit.MILLISECONDS);
}
間隔指的是連續(xù)兩次任務(wù)開始執(zhí)行的間隔。
對于scheduleAtFixedRate方法,當(dāng)執(zhí)行任務(wù)的時(shí)間大于我們指定的間隔時(shí)間時(shí),它并不會在指定間隔時(shí)開辟一個(gè)新的線程并發(fā)執(zhí)行這個(gè)任務(wù)。而是等待該線程執(zhí)行完畢。
2.按指定頻率間隔執(zhí)行某個(gè)任務(wù)。
初始化時(shí)延時(shí)0ms開始執(zhí)行,本次執(zhí)行結(jié)束后延遲100ms開始下次執(zhí)行。
/**
* 以固定延遲時(shí)間進(jìn)行執(zhí)行
* 本次任務(wù)執(zhí)行完成后,需要延遲設(shè)定的延遲時(shí)間,才會執(zhí)行新的任務(wù)
*/
public static void executeFixedDelay() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleWithFixedDelay(
new EchoServer(),
0,
100,
TimeUnit.MILLISECONDS);
}
間隔指的是連續(xù)上次執(zhí)行完成和下次開始執(zhí)行之間的間隔。
3.周期定時(shí)執(zhí)行某個(gè)任務(wù)。
有時(shí)候我們希望一個(gè)任務(wù)被安排在凌晨3點(diǎn)(訪問較少時(shí))周期性的執(zhí)行一個(gè)比較耗費(fèi)資源的任務(wù),可以使用下面方法設(shè)定每天在固定時(shí)間執(zhí)行一次任務(wù)。
/**
* 每天晚上8點(diǎn)執(zhí)行一次
* 每天定時(shí)安排任務(wù)進(jìn)行執(zhí)行
*/
public static void executeEightAtNightPerDay() {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
long oneDay = 24 * 60 * 60 * 1000;
long initDelay = getTimeMillis("20:00:00") - System.currentTimeMillis();
initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;
executor.scheduleAtFixedRate(
new EchoServer(),
initDelay,
oneDay,
TimeUnit.MILLISECONDS);
}
/**
* 獲取指定時(shí)間對應(yīng)的毫秒數(shù)
* @param time "HH:mm:ss"
* @return
*/
private static long getTimeMillis(String time) {
try {
DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");
Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);
return curDate.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
3、Spring
除了我們自己實(shí)現(xiàn)定時(shí)任務(wù)之外,我們可以使用Spring幫我們完成這樣的事情。
Spring自動定時(shí)任務(wù)配置方法(我們要執(zhí)行任務(wù)的類名為com.study.MyTimedTask)
<bean id="myTimedTask" class="com.study.MyTimedTask"/>
<bean id="doMyTimedTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myTimedTask"/>
<property name="targetMethod" value="execute"/>
<property name="concurrent" value="false"/>
</bean>
<bean id="myTimedTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="doMyTimedTask"/>
<property name="cronExpression" value="0 0 2 * ?"/>
</bean>
<bean id="doScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="myTimedTaskTrigger"/>
</list>
</property>
</bean>
<bean id="doScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<bean class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail"/>
<bean id="doMyTimedTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="com.study.MyTimedTask"/>
</property>
<property name="targetMethod" value="execute"/>
<property name="concurrent" value="false"/>
</bean>
</property>
<property name="cronExpression" value="0 0 2 * ?"/>
</bean>
</list>
</property>
</bean>
|