【定时任务】Timer
什么是Timer?
Timer是线程安排任务以供将来在后台线程中执行的工具。 任务可以安排为一次性执行,或定期重复执行。
对应于每个Timer对象的是一个单独的后台线程,用于按顺序执行所有计时器的任务。 计时器任务应该很快完成。 如果一个计时器任务花费过多的时间来完成,它会“占用”计时器的任务执行线程。 反过来,这可能会延迟后续任务的执行,这些任务可能会“聚集”并在(如果)有问题的任务最终完成时快速连续执行。
- 
之所以这样是因为:
重复任务的第一次执行的时间、第二次执行的时间、第三....是以及确定好了的。
比如说:第一次执行是10:00:00 , 每五秒执行一次,那么其实第二次的时间就是 10:00:05,第三次就是10:00:10。但是如果第一次执行的时间就超过了30s,那么当进行如下判断的时候就直接为true,任务执行。而不能达到我们所需要的效果,就是每个任务执行完成后过5s执行下一个任务。
 
if (taskFired = (executionTime<=currentTime)) {
}
 详细如下:
     */
    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        break; // Queue is empty and will forever remain; die
                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized(task.lock) {
                        if (task.state == TimerTask.CANCELLED) {
                            queue.removeMin();
                            continue;  // No action required, poll queue again
                        }
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        if (taskFired = (executionTime<=currentTime)) {
                            if (task.period == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }
在对Timer对象的最后一个实时引用消失并且所有未完成的任务都已完成执行后,计时器的任务执行线程将正常终止(并成为垃圾收集的对象)。 但是,这可能需要任意长的时间才能发生。 默认情况下,任务执行线程不作为守护线程运行,因此它能够防止应用程序终止。 如果调用者想快速终止定时器的任务执行线程,调用者应该调用定时器的取消方法。
如果计时器的任务执行线程意外终止,例如,因为它的stop方法被调用,任何进一步尝试在计时器上安排任务都将导致IllegalStateException ,就好像计时器的取消方法已被调用一样。
- 原因是被安排的任务的状态会被修改:
 
        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");
            synchronized(task.lock) {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }
此类是线程安全的:多个线程可以共享单个Timer对象,而无需外部同步。
- 原因是因为任务队列的操作以及单个任务的操作都进行了加锁。
 
在内部,它使用一个二叉堆来表示它的任务队列,所以调度一个任务的成本是 O(log n),其中 n 是并发调度的任务数。
此类不提供实时保证:它使用Object.wait(long)方法调度任务。
Java 5.0 引入了java.util.concurrent包,其中的并发实用程序之一是ScheduledThreadPoolExecutor ,它是一个线程池,用于以给定的速率或延迟重复执行任务。 它实际上是Timer / TimerTask组合的更通用的替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类化TimerTask (只需实现Runnable )。 使用一个线程配置ScheduledThreadPoolExecutor使其等效于Timer 。
实施说明:此类可扩展到大量并发计划任务(数千个应该没有问题)。
Timer中的关键组件
- 
TimerThread
本质上就是一个线程,这个线程的作用就是死循环执行TaskQueue中的任务(线程)。
 - 
TaskQueue
本质上可以理解为 以 平衡二叉树 的数据结构组织的 TimerTask数组。(表现为平衡二叉树)
 - 
TimerTask
本质上是一个线程,但是包含了其他一些属性,如:任务状态,任务间隔,下次执行时间等。
 
                    
                
                
            
        
浙公网安备 33010602011771号