被遗弃的Java原生Timer

  java.util.Timer是从jdk1.3版本就存在的java原生定时器实现,现在做项目已经不推荐使用它来实现定时任务,为什么呢?让我们从源码上一探究竟。

原因分析

  1. 只有一个线程执行定时任务,一个Timer多个任务的情况下,不能保证任务按指定定时策略执行。
    如果前一个定时任务执行太久,超过后一个定时任务的定时间隔,后一个任务会延时执行。
    整个Timer采用“生产者—消费者”模式实现。TaskQueue queue存储定时任务,TimerThread thread执行定时任务。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * The timer task queue. This data structure is shared with the timer
    * thread. The timer produces tasks, via its various schedule calls,
    * and the timer thread consumes, executing timer tasks as appropriate,
    * and removing them from the queue when they're obsolete.
    */

    private final TaskQueue queue = new TaskQueue();

    /**
    * The timer thread.
    */

    private final TimerThread thread = new TimerThread(queue);

    TimerTask task.run() 不会开新线程,如果阻塞,后面的任务都会阻塞。

  2. 只有一个执行定时任务的线程,如果这个线程出现异常而终止,则整个定时任务就终止了,没有可靠性保证。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    TimerTask t1 = new TimerTask() {

    @Override
    public void run() {
    // TODO Auto-generated method stub
    System.out.println("t1 run");
    int a = 1/0;
    }
    };
    TimerTask t2 = new TimerTask() {

    @Override
    public void run() {
    // TODO Auto-generated method stub
    System.out.println("t2 run");
    }
    };
    Timer timer = new Timer("Timer");
    timer.scheduleAtFixedRate(t1, 2000, 1000);
    timer.scheduleAtFixedRate(t2, 1000, 1000);

    程序输出:
    t2 run
    t2 run
    t1 run
    报除零错,定时线程异常结束,整个定时器结束。

结论

  原生Timer已不适合在工程项目中使用,不过看看源码,学习下Java库开发者的思想及实现方法还是可取的。