(1)API使用
1.延迟x毫秒之后再执行制定代码
先new一个Timer对象,再调用schedule方法。
public void schedule(TimerTask task,long delay)
例子:new Timer().schedule(new TimerTask() {
@Override
public void run() {
System.out.println("this is a timer");
}
},3*1000);
结果:三秒之后打印this is a timer
2.延迟x毫秒之后执行,且第一次执行之后每隔y毫秒执行一次
public void schedule(TimerTask task,long delay,long period)
例子:
new Timer().schedule(new TimerTask() {
@Override
public void run() {
System.out.println(System.currentTimeMillis()+": " +"this is a timer");
}
},3*1000,2*1000);
结果:
1415973070731: this is a timer
1415973072731: this is a timer
1415973074731: this is a timer
1415973076731: this is a timer
public void schedule(TimerTask task,Date time)
例子:
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
new Timer().schedule(new TimerTask() {
@Override
public void run() {
System.out.println(System.currentTimeMillis()+": " +"this is a timer");
}
},calendar.getTime());
4.在指定时间执行,并且第一次执行之后每隔period后执行一次
public void schedule(TimerTask task, Date firstTime, long period)
例子:
public static void main(String[] args)
{
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run()
{
System.out.println(System.currentTimeMillis()+": " +"this is a timer");
}
}, calendar.getTime(), 5*1000);
}
结果为:
1421988927613: this is a timer
1421988932613: this is a timer
1421988937613: this is a timer
1421988942614: this is a timer
1421988947618: this is a timer
那么如何让解决呢?可以使用scheduleAtFixedRate方法,也就是只算理论时间,如第8s被调度,那么计算出的下次执行时间就是按照理论上的精确时间来计算的,也就是第10s来执行
5.在指定时间执行,并且第一次执行之后每隔period后执行一次(按理论计算得来的时间)
public static void main(String[] args)
{
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run()
{
System.out.println(System.currentTimeMillis()+": " +"this is a timer");
}
}, calendar.getTime(), 5*1000);
}
结果为:
1421989854378: this is a timer
1421989859378: this is a timer
1421989864378: this is a timer
1421989869379: this is a timer
1421989874381: this is a timer
(2)Timer构造函数分析
1.无参构造函数
public Timer()
{
this("Timer-" + serialNumber());
}
就是简单的为线程指定一个名字,前缀为Timer
2.为线程指定一个名字
public Timer(String name)
{
thread.setName(name);
thread.start();
}
3.定时器线程是否需要和进程的生命周期一样(如果一样,那么进程结束了定时器就会结束) public Timer(boolean isDaemon)
{
this("Timer-" + serialNumber(), isDaemon);
}
/**
* The timer thread.
*/
private final TimerThread thread = new TimerThread(queue);
其中的TimerThread类定义为:
class TimerThread extends Thread {
看到这里,就知道Timer内部封装了一个线程,用来做独立于外部线程的调度
可以看到new TimerThread的时候传入了一个queue:
private final TaskQueue queue = new TaskQueue();
看名字就知道是一个队列,队列里面是要调度的任务
class TaskQueue {
private TimerTask[] queue = new TimerTask[128];
(3)Timer调度函数分析
1.当前时间x毫秒后执行一次
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
这里调用了sched方法,将task传入,第一个参数传入System.currentTimeMillis()+delay可以看出第一次执行的时间点为当前时间推迟x毫秒,而这里第三个参数传入0,说明时间片为0,代表隔多久执行一次,0表示以后不执行
2.当前时间x毫秒后执行一次,以后每隔period毫秒执行一次
public void schedule(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, -period);
}
这里period变为负数,只是理解不同,没有特别意义,可以忽略
3.当前时间x毫秒后执行一次,以后每隔period毫秒执行一次(按理论时间)
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, period);
}
唯一的区别就是period没有取反,作用也就是为了在sched中区别scheduleAtFixedRate和schedule
下面来看下sched方法:
private void sched(TimerTask task, long time, long period)
{
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue)
{
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
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();
}
}