java Timer和ScheduledThreadPoolExecutor使用

方法:schedulescheduleAtFixedRate区别:

两者都可以作为定时器,定时的刷新功能,但又有区别:

当计划反复执行的任务时,如果你注重任务执行的平滑度,那么请使用schedule方法,如果你在乎的是任务的执行频度那么使用scheduleAtFixedRate方法。 例如,这里使用了schedule方法,这就意味着所有beep之间的时间间隔至少为1秒,也就是说,如果有一个beap因为某种原因迟到了(未按计划执行),那么余下的所有beep都要延时执行。如果我们想让这个程序正好在3秒以后终止,无论哪一个beep因为什么原因被延时,那么我们需要使用scheduleAtFixedRate方法,这样当第一个beep迟到时,那么后面的beep就会以最快的速度紧密执行(最大限度的压缩间隔时间)

简单讲:
schedule注重时间间隔的稳定性。
scheduleAtFixedRate更注重保持执行频率的稳定.
下面进行图解:

注意问题:

  • 每一个Timer仅对应唯一一个线程。
  • Timer不保证任务执行的十分精确。
  • Timer类的线程安全的。

终止Timer线程

  1. 调用Timer.cancle()方法。可以在程序任何地方调用,甚至在TimerTask中的run方法中调用;
  2. 创建Timer时定义位daemon守护线程(有关守护线程见《Java守护线程》),使用new Timer(true)语句;
  3. 设置Timer对象为null,其会自动终止;
  4. 调用System.exit方法,整个程序终止。

Timer线程的缺点

  1. Timer线程不会捕获异常,所以TimerTask抛出的未检查的异常会终止timer线程。如果Timer线程中存在多个计划任务,其中一个计划任务抛出未检查的异常,则会引起整个Timer线程结束,从而导致其他计划任务无法得到继续执行。
  2. Timer线程时基于绝对时间(如:2014/02/14 16:06:00),因此计划任务对系统的时间的改变是敏感的。
  3. Timer是单线程,如果某个任务很耗时,可能会影响其他计划任务的执行。

升级版:ScheduledThreadPoolExecutor

构造方法

  1. ScheduledThreadPoolExecutor(int corePoolSize) 使用给定核心池大小创建一个新定定时线程池
  2. ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactorythreadFactory) 使用给定的初始参数创建一个新对象,可提供线程创建工厂

调度方法

  1. schedule(Callable callable, long delay, TimeUnit unit); 延迟delay时间后开始执行callable

  2. scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); 延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,当任务执行时间大于间隔时间时,之后的任务都会延迟,此时与Timer中的schedule方法类似

  3. scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); 延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,这里的间隔时间delay是等上一个任务完全执行完毕才开始计算,与Timer中scheduleAtFixedRate情况不同

方法:scheduleAtFixedRatescheduleWithFixedDelay区别

看图解

与Timer相比,优点有:

  1. ScheduledThreadPoolExecutor线程会捕获任务重的异常,即使多个计划任务中存在某几个计划任务为捕获异常的情况,也不会影响ScheduledThreadPoolExecutor总线程的工作,不会影响其他计划任务的继续执行。

  2. ScheduledThreadPoolExecutor是基于相对时间的,对系统时间的改变不敏感,但是如果执行某一绝对时间(如2014/02/14 17:13:06)执行任务,可能不好执行,此时可使用Timer。

  3. ScheduledThreadPoolExecutor是线程池,如任务数过多或某些任务执行时间较长,可自动分配更多的线程来执行计划任务。

既然这么好,那么如何使用?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestScheduledThreadPoolExecutor {
public static void main(String[] args) {
ScheduledThreadPoolExecutor exec=new ScheduledThreadPoolExecutor(1);
exec.scheduleAtFixedRate(new Runnable(){//每隔一段时间就触发异常
@Override
public void run() {
throw new RuntimeException();
}}, 1000, 5000, TimeUnit.MILLISECONDS);
exec.scheduleAtFixedRate(new Runnable(){//每隔一段时间打印系统时间,证明两者是互不影响的
@Override
public void run() {
System.out.println(System.nanoTime());
}}, 1000, 2000, TimeUnit.MILLISECONDS);
}
}

如何进行关闭

scheduleTime.shutdown();

以上摘自:

Java定时任务Timer、TimerTask与ScheduledThreadPoolExecutor详解
Timer和TimerTask详解