Timer 类的使用以及源码分析

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

//只执行一次
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的是线程安全的.

有任何问题,欢迎指出

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容