Java的定时/计划功能功能
- 定时器Timer相关类的使用
- Timer相关API
- void schedule(TimerTask task, Date time)
- void cancel()销毁Timer线程
- 执行时间花费过长,影响接下来执行的时间
- void scheduleAtFixedRate(TimerTask task, Date firstTime,long period) 在指定日期之后重复周期执行该任务,如果起始时间在以前则立即执行
- Timer和TimerTask的cancel()方法
- schedule(TimerTask task,long delay,long period)定时间隔执行任务
- void scheduleAtFixedRate(TimerTask task, long delay, long period) 具有追赶的特性
定时器Timer相关类的使用
- Timer类
设置计划任务,在指定时间开始执行某一任务 - TimerTask抽象abstract类
封装任务 - TimerTask的子类
执行具体执行任务
Timer相关API
void schedule(TimerTask task, Date time)
在指定时间执行一次任务,如果设置的时间已经超过则立即执行
//定时器
class AB{
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
System.out.println("当前时间为:"+now);
long start = now + 1000;
System.out.println("计划开始时间为:"+start);
Timer timer = new Timer();
Thread.sleep(100);
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("已经执行任务,时间为:" + System.currentTimeMillis());
}
};
timer.schedule(timerTask,new Date(start));
System.out.println("main线程走完时间为:"+System.currentTimeMillis());
}
}
timer对象是执行定时任务
timerTask抽象类实现了Runable接口,其子类是执行具体的代码逻辑,重写run方法的
执行结果如下图
注意:此时main方法走完之后,定时线程因为不是守护线程还在继续走下去。但是定时任务走完之后线程并没有结束,还在运行
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();
}
}
执行schedule方法的时候将TimerTask加入queue的队列中
然后一直true死循环查找队列,如果队列为空则释放锁,但是死循环还是一直执行。所以线程不销毁
void cancel()销毁Timer线程
一定要注意虽然可以在run方法内部或者主线程使用,但是一定要确保调用此方法时是最后一条任务结束了,否则所有后续的定时任务都会失效
执行时间花费过长,影响接下来执行的时间
class AD{
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis();
System.out.println("当前时间为:"+now);
long start = now + 1000;
System.out.println("计划1开始时间为:"+start);
long start2 = now + 2000;
System.out.println("计划2开始时间为:" + start2);
Timer timer = new Timer();
Thread.sleep(100);
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("已经执行1任务,时间为:" + System.currentTimeMillis());
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行1任务完毕,时间为:" + System.currentTimeMillis());
}
};
TimerTask timerTask2 = new TimerTask() {
@Override
public void run() {
System.out.println("已经执行2任务,时间为:" + System.currentTimeMillis());
}
};
timer.schedule(timerTask,new Date(start));
timer.schedule(timerTask2,new Date(start2));
// Thread.sleep(2000);
// timer.cancel();
System.out.println("main线程走完时间为:"+System.currentTimeMillis());
}
}
因为只有1个线程去执行,所以被阻塞了
void scheduleAtFixedRate(TimerTask task, Date firstTime,long period) 在指定日期之后重复周期执行该任务,如果起始时间在以前则立即执行
Timer和TimerTask的cancel()方法
TimerTask类的cancel方法是取消自身在队列queue的任务
Timer类的cancel方法是取消所有queue的任务
但不是会立即取消任务,有时候会没有抢到queue队列的锁,导致线程继续执行
class AH extends TimerTask {
private int i;
public AH(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println("第" + i + "次没有被cancel取消");
}
}
class AG {
public static void main(String[] args) {
int i = 0;
long now = System.currentTimeMillis();
System.out.println("当前时间为:" + now);
System.out.println("计划时间为:" + now);
while (true) {
i++;
Timer timer = new Timer();
AH ah = new AH(i);
timer.schedule(ah, new Date(now));
timer.cancel();
}
}
}
还是有没有抢到锁,继续执行的现象
schedule(TimerTask task,long delay,long period)定时间隔执行任务
不具有追赶的特性,从上一个任务结束的时间到下一个任务开始的时间
void scheduleAtFixedRate(TimerTask task, long delay, long period) 具有追赶的特性
具有追赶的特性,从上一个任务结束开始的时间到下一个任务开始的时间
例如Spring的@Schedule注解每个整点进行一次任务,其实用的底层是Excuter并发框架的定时
Comments | 0 条评论