1.基本简介
java.util.TimerTask:表示一个定时任务
基本使用:
TimerTask task1=new TimerTask() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
}
};
java.util.Timer:定时器,主要负责定时任务的调度和执行
核心方法介绍
//单次执行:当前时间延迟:delay毫秒后运行task
public void schedule(TimerTask task, long delay);
//单次执行:在绝对时间 time的时候执行task
public void schedule(TimerTask task, Date time);
//固定延迟重复执行:第一次的执行时间是当前时间+delay
public void schedule(TimerTask task, long delay, long period);
//固定延迟重复执行:第一次执行时间是:firstTime
//后一次的执行时间是前一次的实际执行时间+period
public void schedule(TimerTask task, Date firstTime, long period);
//固定频率重复执行:第一次执行时间是:firstTime
//后一次的执行时间是前一次的实际执行时间+period
public void scheduleAtFixedRate(TimerTask task, long delay, long period);
//固定频率重复执行:第一次的执行时间是当前时间+delay
public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period);
简单说明:
(1)对于固定延时,它是基于上次任务的“实际”执行时间来算的,如果因为某些原因,上次任务延时了,则本次任务也会延时,而固定频率会尽量补够运行次数。
(2)如果第一个执行计划的时间:firstTime是一个过去时间,就会立即执行。
基本原理:
(1)Timer内部是有任务队列和Timer线程组成。
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
(2)任务队列是按照下次的执行时间来优先排序的。
(3)一个Timer对象只有一个Timer线程,所以当一个Timer对象执行多个TimerTask任务时,会出现堵塞的现象。
2.情景一:普通的使用
(1)使用TimerTask定义任务
(2)Timer 的 schedule方法进行任务的调度
import java.util.Timer;
import java.util.TimerTask;
public class Test {
public static void main(String[] args) {
TimerTask task=new TimerTask() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务:"+System.currentTimeMillis()+"]");
}
};
Timer timer=new Timer();
timer.schedule(task,100,3000);
}
}
效果:可发现是单线程的,一直用的是Timer-0线程
3.情景二:一个Timer执行多个Task,堵塞现象
(1)定义了两个TimerTask,其中一个TimerTask中使用线程睡眠10秒
TimerTask task1=new TimerTask() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
}
};
TimerTask task2=new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
}
};
Timer timer=new Timer();
timer.schedule(task2,1000);
timer.schedule(task1,100,3000);
效果:会堵塞10秒,然后再继续执行Task1的循环定时任务,看源码可知,Timer执行任务时单线程。
4.情景三:出现异常的情况
强调:在执行任何一个任务的run方法时,一旦run抛出了异常,Timer线程就会退出,从而所有定时任务都会被取消。如果希望各个定时任务互不干扰,一定要在run方法内捕获所有异常。
TimerTask task1=new TimerTask() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
}
};
TimerTask task2=new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
throw new RuntimeException("抛出个异常玩玩");
}
};
Timer timer=new Timer();
timer.schedule(task1,100,3000);
timer.schedule(task2,1000);
现象:
搞两个Timer去分别跑任务,并不会影响
TimerTask task1=new TimerTask() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务1:"+System.currentTimeMillis()+"]");
}
};
TimerTask task2=new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println("[当前线程是:"+name+",执行定时任务2:"+System.currentTimeMillis()+"]");
throw new RuntimeException("抛出个异常玩玩");
}
};
Timer timer1=new Timer();
Timer timer2=new Timer();
timer1.schedule(task1,100,3000);
timer2.schedule(task2,1000);
现象: