美文网首页
Timer 类的使用以及源码分析

Timer 类的使用以及源码分析

作者: EdwardWinner | 来源:发表于2019-05-25 18:56 被阅读0次

    根据是否循环执行分为两类:

    //只执行一次
    public void schedule(TimerTask task, long delay);
    public void schedule(TimerTask task, Date time);
    
    //循环执行
    //在循环执行类别中根据循环时间间隔又可以分为两类
    public void schedule(TimerTask task, long delay, long period) ;
    public void schedule(TimerTask task, Date firstTime, long period) ;
    
    public void scheduleAtFixedRate(TimerTask task, long delay, long period)
    public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
    

    只执行一次

    Timer timer = new Timer();
    //延迟1000ms执行程序
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
        }
    }, 1000);
    //延迟10000ms执行程序
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
        }
    }, new Date(System.currentTimeMillis() + 10000));
    

    循环执行

    Timer timer = new Timer();         
    //前一次执行程序结束后 2000ms 后开始执行下一次程序
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
        }
    }, 0,2000);
    
    //前一次程序执行开始 后 2000ms后开始执行下一次程序
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
        }
    },0,2000);
    

    源码分析

    Timer

    public class Timer {
    
    //维护TaskQueue
    private final TaskQueue queue = new TaskQueue();
    //维护TimerThread
    private final TimerThread thread = new TimerThread(queue);
    
    private final Object threadReaper = new Object() {
        protected void finalize() throws Throwable {
            synchronized(queue) {
                thread.newTasksMayBeScheduled = false;
                queue.notify(); // In case queue is empty.
            }
        }
    };
    
    //使用原子操作类来保证count的准确性
    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
    
    //getAndIncrement的实现方式,不断的调用compareAndSwapInt方法
    //返回的是旧值
    private static int serialNumber() {
        return nextSerialNumber.getAndIncrement();
    }
    
    public Timer() {
        this("Timer-" + serialNumber());
    }
    
    public Timer(boolean isDaemon) {
        this("Timer-" + serialNumber(), isDaemon);
    }
    
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }
    
    //根据传入的参数,决定是否设置守护进程
    public Timer(String name, boolean isDaemon) {
        thread.setName(name);
        thread.setDaemon(isDaemon);
        thread.start();
    }
    
    public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, 0);
    }
    
    public void schedule(TimerTask task, Date time) {
        sched(task, time.getTime(), 0);
    }
    
    public void schedule(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, -period);
    }
    
    public void schedule(TimerTask task, Date firstTime, long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), -period);
    }
    
    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, period);
    }
    
    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
                                    long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), period);
    }
    
    //核心代码:
    private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");
    
        // Constrain value of period sufficiently to prevent numeric
        // overflow while still being effectively infinitely large.
        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
            period >>= 1;
    
        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");
    
            synchronized(task.lock) {
                //如果当前TimerTask的状态不等于VIRGIN,那么抛出异常
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }
    
            //将TimerTask添加至TaskQueue
            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }
    
    //取消Timer,reset状态,且清除queue
    public void cancel() {
        synchronized(queue) {
            thread.newTasksMayBeScheduled = false;
            queue.clear();
            queue.notify();  // In case queue was already empty.
        }
    }
    
     //从TaskQueue中移除掉所有已经取消的TimerTask,这个方法不会对Timer的行为造成影响,但是从队列中删除对已取消任务的引用。大多数的项目中都不需要调用此方法,它是为少数几个取消大量任务的应用程序而设计的。
     public int purge() {
         int result = 0;
         synchronized(queue) {
             for (int i = queue.size(); i > 0; i--) {
                 if (queue.get(i).state == TimerTask.CANCELLED) {
                     queue.quickRemove(i);
                     result++;
                 }
             }
             if (result != 0)
                 queue.heapify();
         }
         return result;
     }
    }
    

    TimerThread

    /**
    * This "helper class" implements the timer's task execution thread, which
    * waits for tasks on the timer queue, executions them when they fire,
    * reschedules repeating tasks, and removes cancelled tasks and spent
    * non-repeating tasks from the queue.
    */
    class TimerThread extends Thread {
    
    boolean newTasksMayBeScheduled = true;
    
    private TaskQueue queue;
    
    TimerThread(TaskQueue queue) {
        this.queue = queue;
    }
    
    public void run() {
        try {
            mainLoop();
        } finally {
            // Someone killed this Thread, behave as if Timer cancelled
            synchronized(queue) {
                newTasksMayBeScheduled = false;
                queue.clear();  // Eliminate obsolete references
            }
        }
    }
    
    //死循环,不断的取TimerTask
    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())
                       // Queue is empty and will forever remain; die
                        break; 
    
                    // 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) {
          }
        }
      }
    }
    

    TaskQueue

    class TaskQueue {
    
    //维护一个长度为128的TimerTask数组
    private TimerTask[] queue = new TimerTask[128];
    
    private int size = 0;
    
    int size() {
        return size;
    }
    
    //添加TimerTask到queue中
    void add(TimerTask task) {
        // Grow backing store if necessary
        if (size + 1 == queue.length)
            queue = Arrays.copyOf(queue, 2*queue.length);
    
        queue[++size] = task;
        fixUp(size);
    }
    
    //获取最小index的TimerTask
    TimerTask getMin() {
        return queue[1];
    }
    
    //根据index返回对应的TimerTask
    TimerTask get(int i) {
        return queue[i];
    }
    
    //移除掉最小的TimerTask
    void removeMin() {
        queue[1] = queue[size];
        queue[size--] = null;  // Drop extra reference to prevent memory leak
        fixDown(1);
    }
    
    //快速移除指定Index的TimerTask
    void quickRemove(int i) {
        assert i <= size;
    
        queue[i] = queue[size];
        queue[size--] = null;  // Drop extra ref to prevent memory leak
    }
    
    //重新制定执行时间
    void rescheduleMin(long newTime) {
        queue[1].nextExecutionTime = newTime;
        fixDown(1);
    }
    
    //判断当前数组的大小
    boolean isEmpty() {
        return size==0;
    }
    
    //清除所有的TimerTask
    void clear() {
        // Null out task references to prevent memory leak
        for (int i=1; i<=size; i++)
            queue[i] = null;
    
        size = 0;
    }
    
    private void fixUp(int k) {
        while (k > 1) {
            int j = k >> 1;
            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
                break;
            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
            k = j;
        }
    }
    
    private void fixDown(int k) {
        int j;
        while ((j = k << 1) <= size && j > 0) {
            if (j < size &&
                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
                j++; // j indexes smallest kid
            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
                break;
            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
            k = j;
        }
    }
    
    //堆化
    void heapify() {
        for (int i = size/2; i >= 1; i--)
            fixDown(i);
        }
    }
    

    TimerTask

    public abstract class TimerTask implements Runnable {
    
    final Object lock = new Object();
    
    int state = VIRGIN;
    
    //原始状态的
    static final int VIRGIN = 0;
    
    //已排程的
    static final int SCHEDULED   = 1;
    
    //执行中的
    static final int EXECUTED    = 2;
    
    //取消的
    static final int CANCELLED   = 3;
    
    //下一次执行时间
    long nextExecutionTime;
    
    long period = 0;
    
    protected TimerTask() {
    }
    public abstract void run();
    
    //修改TimerTask的状态
    public boolean cancel() {
        synchronized(lock) {
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }
    
    //如果period小于0,那么返回下一次执行时间+周期
    //如果period大于0,那么返回下一次执行时间-周期
    public long scheduledExecutionTime() {
        synchronized(lock) {
            return (period < 0 ? nextExecutionTime + period
                               : nextExecutionTime - period);
            }
        }
    }
    

    Timer执行流程:

    • 当Timer被创建成功之后,唯一一个线程TimerThread将开始执行
    • 不断的从TimerQueue中获取TimerTask
    • 判断TimerTask的状态、时间,如果时间被用完,那么移除TimerTask,否则调用TimerTask的run方法
    • 当TimerTask需要取消时,可以调用TimerTask的cancel方法
    • 当Timer需要取消时,调用Timer.cancel方法

    总结:

    • TimerTask 只能被schedule一次,然后被cancel后,就不能再被schedule调用,否则会抛异常。java.lang.IllegalStateException: TimerTask is canceled.
    • 需要反复注册任务的话,只能重建TimerTask.
    • TimerThread的TimerTask是存在执行顺序的.
    • Timer不保证任务执行的十分精确,schedule函数尽量让每一次间隔精准,而scheduleAtFixedRate则是,尽量在算好的时间执行.
    • TimerThread的是线程安全的.

    有任何问题,欢迎指出

    相关文章

      网友评论

          本文标题:Timer 类的使用以及源码分析

          本文链接:https://www.haomeiwen.com/subject/zjvzzqtx.html