1.用timer缺点非常大
Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
我们关于定时/周期操作都是通过Timer来实现的。但是Timer有以下几种危险
a. Timer是基于绝对时间的。容易受系统时钟的影响。
b. Timer只新建了一个线程来执行所有的TimeTask。所有TimeTask可能会相关影响
c. Timer不会捕获TimerTask的异常,只是简单地停止。这样势必会影响其他TimeTask的执行。
2.ScheduledThreadPoolExecutor
鉴于 Timer 的上述缺陷,Java 5 推出了基于线程池设计的ScheduledThreadPoolExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需 要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。
有以下四个调度器的方法:
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
那么这四个方法有什么区别呢?其实第一个和第二个区别不大,一个是Runnable、一个是Callable,内部包装后是一样的效果;所以把头两个方法几乎当成一种调度,那么三种情况分别是:
1、 进行一次延迟调度:延迟delay这么长时间,单位为:TimeUnit传入的的一个基本单位,例如:TimeUnit.SECONDS属于提供好的枚举信息;(适合于方法1和方法2)。
2、 多次调度,每次依照上一次预计调度时间进行调度,例如:延迟2s开始,5s一次,那么就是2、7、12、17,如果中间由于某种原因导致线程不够用,没有得到调度机会,那么接下来计算的时间会优先计算进去,因为他的排序会被排在前面,有点类似Timer中的:scheduleAtFixedRate方法,只是这里是多线程的,它的方法名也叫:scheduleAtFixedRate,所以这个是比较好记忆的(适合方法3)
3、 多次调度,每次按照上一次实际执行的时间进行计算下一次时间,同上,如果在第7秒没有被得到调度,而是第9s才得到调度,那么计算下一次调度时间就不是12秒,而是9+5=14s,如果再次延迟,就会延迟一个周期以上,也就会出现少调用的情况(适合于方法3);
4、 最后补充execute方法是一次调度,期望被立即调度,时间为空
public class ScheduledThreadPoolExecutorDemo {
public static void main(String[] args) {
ScheduledThreadPoolExecutor scheduledExecutor = new ScheduledThreadPoolExecutor(1);
/**
* new timeTaskForException() 要执行的任务线程
* 1000:延迟多长时间执行
* 2000: 每隔多少长时间执行一次
* TimeUnit.MILLISECONDS:时间单位
*/
scheduledExecutor.scheduleAtFixedRate(new timeTaskForException(), 1000, 2000, TimeUnit.MILLISECONDS);
scheduledExecutor.scheduleAtFixedRate(new timeTaskForPrintSYSTime(), 1000, 3000, TimeUnit.MILLISECONDS);
}
static class timeTaskForException implements Runnable{
public void run() {
throw new RuntimeException();
}
}
static class timeTaskForPrintSYSTime implements Runnable {
public void run() {
System.out.println(System.nanoTime());
}
}
}
来源:oschina
链接:https://my.oschina.net/u/2602705/blog/795493