1.1构造方法
Timer()**:**创建一个新的定时器。
Timer(boolean isDaemon)**:**创建一个新的定时器,true:该定时器关联的线程可以被指定作为守护线程运行。
Timer(String name):创建一个新的定时器,该定时器的关联线程具有指定的名称。
Timer(String name, boolean isDaemon)**:**创建一个新的定时器,该定时器的关联线程可以具有指定的名称,并且可能被指定作为守护线程运行。
1.2常用方法概要
①**void cancel()**
*功能:*终止此计时器,丢弃任何当前计划的任务。
*例如:*time.cancel();
②**int purge()**
*功能:*从这个计时器的任务队列中移除所有已取消的任务。
*例如:*time. purge ();
③**void schedule(TimerTask task, Date time)**
task- task to be scheduled.要调度的任务.
time- time at which task is to be executed. 任务将要被调度的时间点
*功能:*在指定的时间点time上调度执行指定的任务,仅仅调度一次。
*例如:*
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 54);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer.schedule(task,time);
*说明:*任务task将会在当天的15:54:00时被调度一次。
*运行结果:*
2016-08-31 15:53:56
执行次数:0
2016-08-31 15:54:00
④**void schedule(TimerTask task, long delay)**
task- task to be scheduled. 要调度的任务.
delay- delay in milliseconds before task is to be executed. 延迟等待delay(ms)
*功能:*调度一个task,延迟等待指定时间delay(毫秒ms)后开始进行调度,并且仅仅调度一次。
例如:*time*.schedule(task, 5000L);
*说明:*延迟5s=5000ms后调度任务task
*运行结果:*
2016-08-31 15:57:40
执行次数:0
2016-08-31 15:57:45
⑤**void schedule(TimerTask task, Date firstTime, long period)**
task -task to be scheduled.要调度的任务
firstTime -First time at which task is to be executed. 第一次被调度的时间点
period - timein milliseconds between successive task executions.每次调度完至 少等待时间
*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,最少等待period(毫秒ms)后才开始下次调度。重复调度多次。
*例如:*
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer.schedule(task,time,1000L);
*说明:*任务task在16:13:00开始调度,每次调度前最少等待1s
*运行结果:*
2016-08-31 16:14:25
执行次数:0
2016-08-31 16:15:00
执行次数:1
2016-08-31 16:15:01
执行次数:2
2016-08-31 16:15:02
执行次数:3
2016-08-31 16:15:03
执行次数:4
2016-08-31 16:15:04
取消5
⑥**void schedule(TimerTask task, long delay, long period):**
task - taskto be scheduled.要调度的任务
delay - delayin milliseconds before task is to be executed. 第一次被调度延迟等待时间
period - timein milliseconds between successive task executions. 每次调度完至少等待时间
*功能:*调度一个task,在延迟等待delay(毫秒ms)后开始调度,每次调度完后,最少等待period(毫秒ms)后才开始下次调度。重复调度多次。
*例如:*timer.schedule(task, 2000L,1000L);
*说明:*任务task延迟等待2s后开始调度,每次调度前最少等待1s
*运行结果:*
2016-08-31 15:39:55
执行次数:0
2016-08-31 15:39:57
执行次数:1
2016-08-31 15:39:58
执行次数:2
2016-08-31 15:39:59
执行次数:3
2016-08-31 15:40:00
执行次数:4
2016-08-31 15:40:01
取消5
⑦**void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)**
task - task to be scheduled. 要调度的任务
firstTime -First time at which task is to be executed. 第一次被调度的时间点
period - timein milliseconds between successive task executions.每次调度完至 少等待时间
*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,按照指定频度period(ms)优先调用。重复调度多次。
*例如:*
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer.scheduleAtFixedRate(task,time,1000L);
*说明:*任务task在16:15:00开始调度,按照1s的频度进行调度
*运行结果:*
2016-08-31 16:15:45
执行次数:0
2016-08-31 16:16:00
执行次数:1
2016-08-31 16:16:01
执行次数:2
2016-08-31 16:16:02
执行次数:3
2016-08-31 16:16:03
执行次数:4
2016-08-31 16:16:04
取消5
⑧**void scheduleAtFixedRate(TimerTask task, long delay, long period)**
task - taskto be scheduled.要调度的任务
delay - delayin milliseconds before task is to be executed. 第一次被调度延迟等待时间
period - timein milliseconds between successive task executions.每次调度完至 少等待时间
*功能:*调度一个task,在指定时间点firstTime开始调度,每次调度完后,按照指定频度period(ms)优先调用。重复调度多次。
*例如:*
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer.scheduleAtFixedRate(task,time,1000L);
*说明:*任务task在16:15:00开始调度,按照1s的频度进行调度
*运行结果:*
2016-08-31 16:15:45
执行次数:0
2016-08-31 16:16:00
执行次数:1
2016-08-31 16:16:01
执行次数:2
2016-08-31 16:16:02
执行次数:3
2016-08-31 16:16:03
执行次数:4
2016-08-31 16:16:04
取消5
1.3 schedule和scheduleAtFixedRate的比较
schedule**方法:**"fixed-delay":如果上一次执行时间被delay了,随后的执行时间就按照上一次实际执行完成的时间点进行计算;
即:下一次的执行时间点=上一次程序执行完成的时间点+间隔时间
scheduleAtFixedRate**方法:**"fixed-rate":如果上一次执行时间delay了,随后的执行时间按照 上一次开始执行的时间点进行计算,并且为了"catch up"会多次执行任务,TimerTask中的执行体中需要考虑线程同步;
即:下一次的执行时间点**=上一次程序开始执行的时间点+间隔时间;并且如果前一个任务要执**行n秒,而当前任务已经开始执行,因此两个任务间存在重叠,需要考虑线程同步。
当执行任务的时间片大于周期间隔时,会发生什么呢?1). schedule方法:下一次执行时间相对于 上一次实际执行完成的时间点 ,因此执行时间会不断延后2). scheduleAtFixedRate方法:下一次执行时间相对于上一次开始的时间点 ,因此执行时间不会延后,存在并发性,**需要考虑线程同步**
测试实例
import java.util.Timer;
import java.util.TimerTask;
public**class**TimerTest {
static Timer timer = null;
public**staticvoid** main(String[] args) {
timer = new Timer();
//延迟等待2s后,每间隔1s调度,1s间隔时间<执行时间2s
timer.schedule(new TimerWorker(timer),2000L,1000L);
}
}
TimerWorker代码
import java.util.Timer;
import java.util.TimerTask;
public**classTimerWorker extends** TimerTask{
Timertimer= null;
intindex = 0;
public TimerWorker(){}
publicTimerWorker(Timer timer){
this.timer = timer;
}
//编写重复定时任务
@Override
public**void** run() {
if(index < 5){
System.out.println("执行次数:"+index);
try {
Thread.sleep(2000L);//执行时间休眠2s
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("task begin:"+this.scheduledExecutionTime());
index++;
}else{
System.out.println("取消"+index);
timer.cancel();
}
}
}
timer.schedule(new TimerWorker(timer),2000L,1000L);
运行结果:
执行次数:0
task begin:1472635789100
执行次数:1
task begin:1472635791101 = 1472635789100 + 2000
执行次数:2
task begin:1472635793101
执行次数:3
task begin:1472635795102
执行次数:4
task begin:1472635797102
取消5
结论:间隔时间都是2s,下一次的执行时间点**=上一次程序执行完成的时间点+间隔时间** 1s
timer.scheduleAtFixedRate(new TimerWorker(timer),2000L,1000L);
运行结果:
执行次数:0
task begin:1472636554862
执行次数:1
task begin:1472636555862 = 1472636555862 + 1000
执行次数:2
task begin:1472636556862
执行次数:3
task begin:1472636557862
执行次数:4
task begin:1472636558862
取消5
结论:间隔时间都是1s,下一次的执行时间点**=上一次程序开始执行的时间点+间隔时间** 1s,并且前一个任务要执行2秒,而当前任务已经开始执行,因此两个任务间存在重叠,TimerWorker中需要考虑线程同步
1.4测试完整代码
TimerWorker代码如下:
import java.util.Timer;
import java.util.TimerTask;
import com.util.DateUtil;
public**classTimerWorker extends** TimerTask{
Timertimer= null;
intindex = 0;
public TimerWorker(){
}
publicTimerWorker(Timer timer){
this.timer = timer;
}
//编写重复定时任务
@Override
public**void** run() {
if(index < 5){
System.out.println("执行次数:"+index);
System.out.println(DateUtil.getCurrentTimeStr());
index++;
}else{
System.out.println("取消"+index);
timer.cancel();
}
}
}
TimerMain完整代码如下
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
importjava.util.TimerTask;
import com.util.DateUtil;
/**
*@author pjliang
*/
public**class**TimerMain {
static Timer timer = null;
public**staticvoid** main(String[] args) {
timer = new Timer();
TimerWorkertask = newTimerWorker(timer);
System.out.println(DateUtil.getCurrentTimeStr());
//1.延迟5s=5000ms后调度任务task
timer.schedule(task, 5000L);
//2.任务task将会在当天的15:27:00时被调度一次
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 54);
calendar.set(Calendar.SECOND, 0);
Datetime = calendar.getTime();
timer.schedule(task, time);
//3.任务task延迟等待2s后开始调度,每次调度前最少等待1s
timer.schedule(task, 2000L, 1000L);
//4.任务task在16:13:00开始调度,每次调度前最少等待1s
Calendarcalendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);
Datetime = calendar.getTime();
timer.schedule(task, time,1000L);
//5.任务task在16:15:00开始调度,每次调度频度是1s
Calendarcalendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 15);
calendar.set(Calendar.SECOND, 0);
Datetime = calendar.getTime();
timer.scheduleAtFixedRate(task, time,1000L);
//6.任务task在在延迟等待1s后开始调度,每次调度频度是1s
timer.scheduleAtFixedRate(task, 1000L,1L);
}
}
1.5源码分析
构造方法1:无参构造方法,简单通过Timer为前缀构造一个线程名称:
public Timer() {
this("Timer-" + serialNumber());
}
构造方法2:传入了是否为守护线程,守护线程当且仅当主进程结束时,自动注销掉,而无需使用cancel来完成对timer的结束。
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
构造方法3:传递参数name来创建一个自定义名称的timer
public Timer(String name) {
this(name, true);
}
构造方法4:同时传递参数name和isDaemon来创建timer
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
方法**schedule和方法scheduleAtFixedRate的几个重载源码**
1). public void schedule(TimerTask task, long delay)
public**voidschedule(TimerTask task, long** delay) {
if(delay < 0)
throw**new** IllegalArgumentException("Negativedelay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
调用方法sched,
第一个参数task将任务传入;
第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());
第三个参数传入0,该参数代表时间片
2). publicvoid schedule(TimerTask task, long delay, longperiod)
public**voidschedule(TimerTask task, long** delay, longperiod) {
if(delay < 0)
throw**new** IllegalArgumentException("Negativedelay.");
if(period <= 0)
throw**new** IllegalArgumentException("Non-positiveperiod.");
sched(task, System.currentTimeMillis()+delay, -period);
}
调用方法sched,
第一个参数task将任务传入;
第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());
第三个参数传入-period,该参数代表时间片,取反
3). publicvoid scheduleAtFixedRate(TimerTask task, longdelay, long period)
public**voidscheduleAtFixedRate(TimerTask task, long** delay, long period) {
if(delay < 0)
throw**new** IllegalArgumentException("Negativedelay.");
if(period <= 0)
throw**new** IllegalArgumentException("Non-positiveperiod.");
sched(task, System.currentTimeMillis()+delay, period);
}
调用方法sched,
第一个参数task将任务传入;
第二个参数System.currentTimeMillis()是当前时间+延迟时间(如果是Date,参数2就是date.getTime());
第三个参数传入 period,该参数代表时间片,取正
4). privatevoid sched(TimerTask task, long time, longperiod)
private**voidsched(TimerTask task, long** time, longperiod) {
if(time < 0)
throw**new** IllegalArgumentException("Illegalexecution time.");
synchronized(queue){
if (!thread.newTasksMayBeScheduled)
throw**new** IllegalStateException("Timer alreadycancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw**new** IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
queue是一个队列,执行操作的是使用synchronized进行线程同步,所以是线程安全的,随后为task相关参数赋值,有nextExecutionTime(下一次执行时间),period(时间片),state(状态),最后将task放入queue队列中,执行一次notify操作