浅入Timer

目录

一、easy-demo

二、关键类的介绍

1.TimerTask类

2.TaskQueue类

3.TimerThread类

4.Timer类

三、demo的执行流程 


 

 前置知识: ①小顶堆定义、删除、插入等.

                 ②线程的基本知识.

一、easy-demo

四个主要的类:

        ①Timer

        ②TimerThread

        ③TaskQueue

        ④TimerTask

public class TimerDemo {
    public static void main(String[] args) {
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("ThreadName = " + Thread.currentThread().getName() + " Time = " + System.currentTimeMillis());
                System.out.println("定时任务~");
            }
        };
        Timer timer = new Timer();
        long delay = 0;
        long period = 1000;
        //para1:任务逻辑
        //para2:延迟多长时间开始
        //para3:执行周期
        timer.scheduleAtFixedRate(timerTask,0,period);
    }
}

输出结果:每秒执行一次。

ThreadName = Timer-0 Time = 1652606338299
定时任务~
ThreadName = Timer-0 Time = 1652606339309
定时任务~
ThreadName = Timer-0 Time = 1652606340307
定时任务~
ThreadName = Timer-0 Time = 1652606341312
定时任务~

二、关键类的介绍

1.TimerTask类

        TimerTask类的主要属性和方法。

        作用:用户自定义的定时任务逻辑就写在该实例对象中的run方法中。

public abstract class TimerTask implements Runnable {
        //锁对象
        final Object lock = new Object();
        
        //task的4个状态,初始为VIRGIN.
        //①VIRGIN: This task has not yet been scheduled.
        //②SCHEDULED: This task is scheduled for execution
        //③EXECUTED: This non-repeating task has already executed
        //④CANCELLED: This task has been cancelled
        int state = VIRGIN;

        //初始状态
        static final int VIRGIN = 0;

        //已预定状态
        static final int SCHEDULED = 1;

        //已执行状态
        static final int EXECUTED = 2;

        //被取消
        static final int CANCELLED = 3;

        //下一次执行时间(repeat-task)
        long nextExecutionTime;

        //Period in milliseconds for repeating tasks.
        //执行周期  0表示一次性任务 正负值表示周期性任务      
        long period = 0;
        
        protected TimerTask() {
        }

        //TimerTask类实现Runnable,创建该实例类必须重写run()
        public abstract void run();

        //将已预定的task取消,状态变为CANCELLED
        public boolean cancel() {
            synchronized (lock) {
                boolean result = (state == SCHEDULED);
                state = CANCELLED;
                return result;
            }
        }
        
        //设置(重复任务的下一次)执行时间
        public long scheduledExecutionTime() {
            synchronized (lock) {
                return (period < 0 ? nextExecutionTime + period
                        : nextExecutionTime - period);
            }
        }
    }

2.TaskQueue类

任务队列,存放的逻辑结构为小顶堆.

class TaskQueue {
        //The TimerTask with the lowest nextExecutionTime is in queue[1]
        //一个任务队列,初始为2^7的数组.
        //★ 逻辑结构是一个小顶堆,节点权重可视为executeTime 和 currentTime的差值,即最顶部为最先开始执行的task
        private TimerTask[] queue = new TimerTask[128];

        //队列中 number of task
        private int size = 0;

        //Returns the number of tasks currently on the queue.
        int size() {
            return size;
        }

        //Adds a new task to the priority queue.
        //添加一个新的task到队列中,添加到数组末尾,然后进行小顶堆排序
        void add(TimerTask task) {
            //满了就double扩容
            if (size + 1 == queue.length)
                queue = Arrays.copyOf(queue, 2*queue.length);

            queue[++size] = task;
            //★ 小顶堆的插入并排序  细节见下fixUp()方法
            fixUp(size);
        }

        //Return the "head task" of the priority queue.
        //获取最先即将执行的方法
        TimerTask getMin() {
            return queue[1];
        }

        //移除最先即将执行的方法
        //注意:task存在queue[1] ~ queue[n]中,queue[0]不存放.
        void removeMin() {
            //将最后一个task覆盖第一个,然后将最后一个坑置为null. 符合小顶堆删除的规则.
            queue[1] = queue[size];
            queue[size--] = null;
            //★ 进行小顶堆的排序 详细算法见fixDown()方法
            fixDown(1);
        }

        //Removes the ith element from queue without regard for maintaining the heap invariant
        //删除指定位置的task,且不做小顶堆排序.
        void quickRemove(int i) {
            assert i <= size;
            //末尾填坑
            queue[i] = queue[size];
            queue[size--] = null;
        }

        //重新设置队头元素的nextExecutionTime,并且做一次小顶堆排序
        void rescheduleMin(long newTime) {
            queue[1].nextExecutionTime = newTime;
            fixDown(1);
        }

        //判断queue是否为空
        boolean isEmpty() {
            return size==0;
        }

        // Removes all elements from the priority queue.
        void clear() {
            for (int i=1; i<=size; i++)
                queue[i] = null;

            size = 0;
        }

        //小顶堆的排序,每个节点只在该父路径上做排序.
        private void fixUp(int k) {
            //时间复杂度: log2(k)
            while (k > 1) {
                //j为父节点索引
                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;
            //j为左孩子索引
            while ((j = k << 1) <= size && j > 0) {
                if (j < size &&
                        queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
                    //j为小权重的孩子节点
                    j++;
                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);
        }
    }

3.TimerThread类

关键方法是mainLoop

class TimerThread extends Thread {
        //还会有新的task将会被Scheduled
        boolean newTasksMayBeScheduled = true;

        //任务队列
        private TaskQueue queue;

        //构造
        TimerThread(TaskQueue queue) {
            this.queue = queue;
        }

        public void run() {
            try {
                mainLoop();
            } finally {
                synchronized(queue) {
                    newTasksMayBeScheduled = false;
                    queue.clear();
                }
            }
        }

        //执行任务队列的主要方法
        private void mainLoop() {
            while (true) {
                try {
                    TimerTask task;
                    //taskFired为true表示还未达到执行时间,为false表示已经达到可执行时间.
                    boolean taskFired;
                    synchronized(queue) {
                        //队列为空就等待,等待notify()
                        while (queue.isEmpty() && newTasksMayBeScheduled)
                            queue.wait();
                        if (queue.isEmpty())
                            break;

                        long currentTime, executionTime;
                        //获取最先执行的task
                        task = queue.getMin();
                        synchronized(task.lock) {
                            //如果状态为CANCELLED就从队列移除
                            if (task.state == TimerTask.CANCELLED) {
                                queue.removeMin();
                                continue;
                            }
                            currentTime = System.currentTimeMillis();
                            executionTime = task.nextExecutionTime;
                            //taskFired为true表示还未达到执行时间,为false表示已经达到可执行时间.
                            if (taskFired = (executionTime<=currentTime)) {
                                //非重复task
                                if (task.period == 0) { 
                                    //移出队列
                                    queue.removeMin();
                                    //task标志为已执行(实际还未执行)
                                    task.state = TimerTask.EXECUTED;
                                } else { 
                                    //repeat-task
                                    //设置执行周期
                                    //schedule()方法和scheduleAtFixedRate()方法period正负值不同.
                                    queue.rescheduleMin(
                                            task.period<0 ? currentTime   - task.period
                                                    : executionTime + task.period);
                                }
                            }
                        }
                        //等待到执行时间,期间可被唤醒,不被唤醒到时自动醒来.
                        if (!taskFired)
                            queue.wait(executionTime - currentTime);
                    }
                    //到时执行.run方法即用户自定义的定时任务逻辑.
                    if (taskFired)  
                        task.run();
                } catch(InterruptedException e) {
                }
            }
        }
    }

4.Timer类

san在构造方法中可知,new Timer()时,任务线程就已经被start了。

public class Timer {
        //★ 任务队列
        private final TaskQueue queue = new TaskQueue();

        //★ 任务线程
        private final TimerThread thread = new TimerThread(queue);

        //构造
        public Timer(String name) {
            thread.setName(name);
            //new Timer()时,任务线程就启动了.如果任务队列为空,会卡在mainloop里面wait.
            thread.start();
        }

        //schedule方法
        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);
        }

        //scheduleAtFixedRate方法
        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);
        }

        //任务调度核心方法
        private void sched(TimerTask task, long time, long period) {
            if (time < 0)
                throw new IllegalArgumentException("Illegal execution time.");
            if (Math.abs(period) > (Long.MAX_VALUE >> 1))
                period >>= 1;

            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;
                }
                //添加到任务队列中,扔到队尾,然后进行自小而上的小顶堆排序.
                queue.add(task);
                //如果该任务是最先即将执行的任务,就唤醒TimerThread#mainLoop中的queue.wait().
                if (queue.getMin() == task)
                    queue.notify();
            }
        }

        //清空任务队列,与TimerTask中的cancel做区分.
        public void cancel() {
            synchronized(queue) {
                thread.newTasksMayBeScheduled = false;
                queue.clear();
                queue.notify();
            }
        }

        //将任务队列做一次清除,将所有的CANCELLED的task移除,最后做一次小顶堆排序.返回值为移除CANCELLED状态task的数量.
        public int purge() {
            int result = 0;

            synchronized(queue) {
                for (int i = queue.size(); i > 0; i--) {
                    if (queue.get(i).state == TimerTask.CANCELLED) {
                        //移除CANCELLED状态的task.
                        queue.quickRemove(i);
                        result++;
                    }
                }
                
                //有移除就有可能破坏小顶堆规则,需要重排序.
                if (result != 0)
                    queue.heapify();
            }
            return result;
        }
    }

三、demo的执行流程 

多熟悉一下这4个类,再写俩demo进行debug一下就熟悉了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值