Timer的主要作用有以下两个:
- 实现按指定时间执行任务
- 实现按指定周期执行任务
Timer类的主要作用是设置计划任务,即在指定时间开始执行某一个任务。
任务使用TimerTask进行封装
基础使用:
首先要编写TimerTask的子类来定义执行的具体任务:
public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("任务执行了,时间为: "+System.currentTimeMillis());
}
}
然后使用Timer来执行:
public class Test_1 {
public static void main(String[] args) {
try {
long nowTime=System.currentTimeMillis();
System.out.println("当前时间为 "+nowTime);
long scheduletime=nowTime+10000;
MyTask myTask = new MyTask();
Timer timer=new Timer();
Thread.sleep(1000);
timer.schedule(myTask,new Date(scheduletime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可以看到,Timer使用schedule(TimerTask,Date)来在指定的日期执行指定的任务
当我们执行时,会发现线程并未结束,而在持续运行。
线程持续运行的原因:
为什么上面执行完之后,线程并未销毁而在继续运行? ,我们往源码里走:
我们看一下Timer的构造方法:
可以看到,在构造方法中启动了一个新的线程,Timer类用这个新的线程去执行计划任务,找到thread:
发现是TimerThread。这是一个继承Thread的类:
然后去看一下该类重写的run()方法:
发现,里面执行的是mainloop(),那就继续往下找:
mainLoop() 方法里面是一个死循环,新启动的线程并不是守护线程,而且一直在运行。然后该死循环的中断核心逻辑如下:
当队列为空并且newTasksMayBeScheduled这个标记为true的时候,该线程就暂停运行,进行等待。下面判断队列为空时才会退出,但是如果调用schedule()方法的话队列就不可能为空,也就是当newTasksMayBeScheduled这个标记变为false时才有可能退出,那么就找到赋值false的方法:
是在cancel() 方法里面:
不执行 cancel() 方法,则变量newTasksMayBeScheduled的值就不会是false,进程一直呈死循环状态,进程不销毁就是这个原因
当计划时间小于当前时间
那么Timer就会立刻执行该计划任务:
public class Test_1 {
public static void main(String[] args) {
try {
long nowTime=System.currentTimeMillis();
System.out.println("当前时间为 "+nowTime);
long scheduletime=nowTime-1000;
MyTask myTask = new MyTask();
Timer timer=new Timer();
timer.schedule(myTask,new Date(scheduletime));
Thread.sleep(3000);
timer.cancel();
// Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
周期执行计划任务
只要调用 public void schedule(TimerTask task, Date firstTime, long period)
方法即可
public class Test_1 {
public static void main(String[] args) {
try {
long nowTime=System.currentTimeMillis();
System.out.println("当前时间为 "+nowTime);
long scheduletime=nowTime-1000;
MyTask myTask = new MyTask();
Timer timer=new Timer();
timer.schedule(myTask,new Date(scheduletime),4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}