Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说Java定时器——Timer详解[亲测有效],希望能够帮助你!!!。
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
Timer
详解Timer
和TimerTask
用于在后台线程中调度任务的java.util
类。TimerTask
负责任务的执行,Timer
负责任务的调度。
Timer
提供了三种定时模式:
fixed delay
)fixed rate
)Timer
提供了两种方法,应用于不同场景:
//在当前时间往后delay个毫秒开始执行
public void schedule(TimerTask task, long delay) {...}
//在指定的time时间点执行
public void schedule(TimerTask task, Date time) {...}
public static void main(String[] args) {
//定义一个Timer
Timer timer = new Timer("test-timer");
//定义一个TimerTask
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("任务执行时间:" + new Date() + "------------"
+ "线程:" + Thread.currentThread().getName());
}
};
long delay = 3000L;
timer.schedule(task, delay);
System.out.println("任务添加时间:" + new Date() + "------------"
+ "线程:" + Thread.currentThread().getName());
}
工作方式:当达到我们指定的时间,执行一次结束
任务虽然运行结束,但进程没有被销毁。并且执行任务的线程名为我们定义的Timer
的名称。我们看一下源码:
public class Timer {
//小顶堆,用来存放timeTask
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
public Timer(String name) {
thread.setName(name);
thread.start();
}
}
public abstract class TimerTask implements Runnable {
long nextExecutionTime;
long period = 0;
public abstract void run();
}
TaskQueue
:基于小顶堆实现,用来存放timerTask
TimerThread
:任务执行线程,继承Thread
类nextExecutionTime
:假如任务需要多次执行表示下一次执行时间period
:每次任务执行间隔时间run()
:我们执行任务的内容创建一个 Timer
对象就是新启动了一个线程,但是这个新启动的线程,并不是守护线程,它一直在后台运行,通过如下 可以将新启动的 Timer
线程设置为守护线程。我们可以使用以下构造方法(public Timer(boolean isDaemon)
或public Timer(String name, boolean isDaemon)
)来设置。
Fixed Delay
模式//从当前时间开始delay个毫秒数开始定期执行,周期是period个毫秒数
public void schedule(TimerTask task, long delay, long period) {...}
//从指定的firstTime开始定期执行,往后每次执行的周期是period个毫秒数
public void schedule(TimerTask task, Date firstTime, long period){...}
public static void main(String[] args) {
Timer timer = new Timer("test-timer");
MyTimerTask task1 = new MyTimerTask("任务1");
MyTimerTask task2 = new MyTimerTask("任务2");
long delay = 1000L;
long period = 2000L;
timer.schedule(task1, delay, period);
timer.schedule(task2, new Date(), period);
}
static class MyTimerTask extends TimerTask {
private String taskName;
public MyTimerTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(taskName + "执行时间:" + new Date() + "------------"
+ "线程:" + Thread.currentThread().getName());
}
}
工作方式:
TimerThread
没有执行其他任务),如有其他任务在执行,那就需要等到其他任务执行完成才能执行period
时间。根据任务运行结果来看,任务1和任务2并没有按照我们所预期的间隔2秒来执行,基本上间隔都是在6秒。而且我们注册在同一Timer
的任务,都是使用同一个在同一个线程上执行。TimerTask
是以队列的方式一个一个被顺序运行的,所以执行的时间和预期的时间可能不一致,因为前面的任务可能消耗的时间较长,则后面的任务运行的时间会被延迟。延迟的任务具体开始的时间,就是依据前面任务的"结束时间"
Fixed Rate
模式//从当前时间开始delay个毫秒数开始定期执行,周期是period个毫秒数
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {...}
//从指定的firstTime开始定期执行,往后每次执行的周期是period个毫秒数
public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period){...}
public static void main(String[] args) {
Timer timer = new Timer("test-timer");
MyTimerTask task1 = new MyTimerTask("任务1");
MyTimerTask task2 = new MyTimerTask("任务2");
long delay = 1000L;
long period = 5000L;
timer.scheduleAtFixedRate(task1, delay, period);
timer.scheduleAtFixedRate(task2, new Date(System.currentTimeMillis() - 1000L), period);
}
static class MyTimerTask extends TimerTask {
private String taskName;
public MyTimerTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(taskName + "执行时间:" + new Date() + "------------"
+ "线程:" + Thread.currentThread().getName());
}
}
工作方式:
一般情况下和schedule()
方法没有什么区别,我们可以观察结果发现任务2第一次和第二次执行相差4秒,我们设置开始时间为当前时间前1秒,scheduleAtFixedRate()
当计划时间早于当前时间,则任务立即被运行。
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。