1、简介
Timer和TimerTask都是在后台调度任务的java工具类。
简言之:
TimerTask--要做的什么事 (What)
Timer--什么时候做(When)
JavaAPI:Timer & TimerTask
2、关于Timer
在工具类 Timer 中,提供了四个构造方法,每个构造方法都启动了计时器线程。
**Timer()**
*Creates a new timer.*
**Timer(boolean isDaemon)**
*Creates a new timer whose associated thread may be specified to run as a daemon.*
**Timer(String name)**
*Creates a new timer whose associated thread has the specified name.*
**Timer(String name, boolean isDaemon)**
*Creates a new timer whose associated thread has the specified name, and may be specified to run as a daemon.*
同时 Timer 类可以保证多个线程可以共享单个 Timer 对象而无需进行外部同步,所以 Timer 类是线程安全的。但是由于每一个 Timer 对象对应的是单个后台线程,用于顺序执行所有的计时器任务,一般情况下我们的线程任务执行所消耗的时间应该非常短,但是由于特殊情况导致某个定时器任务执行的时间太长,那么他就会“独占”计时器的任务执行线程,其后的所有线程都必须等待它执行完,这就会延迟后续任务的执行,使这些任务堆积在一起。
当程序初始化完成 Timer 后,定时任务就会按照我们设定的时间去执行, Timer 提供了 schedule 方法,该方法有多中重载方式来适应不同的情况:
3、TimerTask
TimerTask是一个实现了Runnable接口的抽象类。
public abstract class TimerTask implements Runnable
它有一个抽象方法 run() 方法,该方法用于执行相应计时器任务要执行的操作。因此每一个具体的任务类都必须继承 TimerTask,然后重写 run() 方法。
此外它还有两个抽象方法:
1、取消该任务
public boolean cancel() {
synchronized(lock) {
boolean result = (state == SCHEDULED);
state = CANCELLED;
return result;
}
}
1)如果该任务只执行一次并且还没有执行,该任务会被取消,永远也不会执行。
2)如果该任务是重复执行,就不会再执行了。(该任务正在运行中的那一次调用了cancel方法,则这一次会完整的执行,此后不会再运行)
2、返回此任务最近实际执行的安排执行时间
public long scheduledExecutionTime() {
synchronized(lock) {
return (period < 0 ? nextExecutionTime + period
: nextExecutionTime - period);
}
}
4、小例子--Getting Start
1、只执行一次,延迟执行
用到的方法:
public void schedule(TimerTask task, long delay) {
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on: " + new Date() + "\n" +
"Thread's name: " + Thread.currentThread().getName());
}
};
Timer timer = new Timer("Timer");
long delay = 1000L;
timer.schedule(task, delay);
}
输出:
Task performed on: Wed Dec 27 22:21:35 CST 2017
Thread's name: Timer
2、指定间隔内重复执行
方法:
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
TimerTask repeatedTask = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
Timer timer = new Timer("Timer");
long delay = 1000L;
long period = 1000L;
timer.scheduleAtFixedRate(repeatedTask, delay, period);
输出:
Task performed on Wed Dec 27 22:48:44 CST 2017
Task performed on Wed Dec 27 22:48:45 CST 2017
Task performed on Wed Dec 27 22:48:46 CST 2017
Task performed on Wed Dec 27 22:48:47 CST 2017
Task performed on Wed Dec 27 22:48:48 CST 2017
````````````````````````````
5、取消Timer & TimerTask
1、TimerTask.cancel()
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
cancel();
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(task, 1000L, 1000L);
输出:
Task performed on Wed Dec 27 22:56:18 CST 2017
2、Timer.cancel()
TimerTask task = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(task, 1000L, 1000L);
Thread.sleep(1000L * 2);
timer.cancel();
输出结果有两种:
这种是在第三次执行之前cancel了。
Task performed on Wed Dec 27 22:59:05 CST 2017
Task performed on Wed Dec 27 22:59:06 CST 2017
Disconnected from the target VM, address: '127.0.0.1:61461', transport: 'socket'
或 在执行第二次的时候,输出结果之前cancel了。
Task performed on Wed Dec 27 23:00:09 CST 2017
Disconnected from the target VM, address: '127.0.0.1:61468', transport: 'socket'
Task performed on Wed Dec 27 23:00:10 CST 2017
6、Timer VS ExecutorService
Timer有许多缺陷,首先 Timer 对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。其次 Timer 线程是不会捕获异常的,如果 TimerTask 抛出的了未检查异常则会导致 Timer 线程终止,同时 Timer 也不会重新恢复线程的执行,他会错误的认为整个 Timer 线程都会取消。同时,已经被安排单尚未执行的 TimerTask 也不会再执行了,新的任务也不能被调度。故如果 TimerTask 抛出未检查的异常,Timer 将会产生无法预料的行为。
除了Timer,还可以利用ExecutorService来调度任务。
一个简单的小例子,利用ExecutorService来重复执行任务:
TimerTask repeatedTask = new TimerTask() {
public void run() {
System.out.println("Task performed on " + new Date());
}
};
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
long delay = 1000L;
long period = 1000L;
executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
Thread.sleep(delay + period * 3);
executor.shutdown();
- Timer 是基于绝对时间的,对系统时间比较敏感,而 ScheduledThreadPoolExecutor 则是基于相对时间;
- Timer 是内部是单一线程,而 ScheduledThreadPoolExecutor 内部是个线程池,所以可以支持多个任务并发执行。
参考:http://www.baeldung.com/java-timer-and-timertask
http://wiki.jikexueyuan.com/project/java-enhancement/java-add1.html