Timer定时调用

1. 具体实例

继承TimerTask抽象类
实现两个子类TimerJob和TimerJob2
package com.husky.timer;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;

/**
 * @author husky
 * @date 2018/9/17 9:41
 */
public class TimerJob extends TimerTask {
    @Override
    public void run() {
        System.out.println("当前执行的任务是TimerJob");
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current time : "+sf.format(date));
        System.out.println("当前线程: "+Thread.currentThread().getName());
    }
}



package com.husky.timer;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;

/**
 * @author husky
 * @date 2018/9/17 10:40
 */
public class TimerJob2 extends TimerTask {
    @Override
    public void run() {
        System.out.println("当前执行的任务是TimerJob2");
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current time : "+sf.format(date));
        System.out.println("当前线程: "+Thread.currentThread().getName());
    }
}


测试类

public class TimerRun {
    public static void main(String[] args) {
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current time:"+sf.format(date));
        System.out.println(Thread.currentThread().getName());
        System.out.println("开始执行定时任务=======");
        Timer timer = new Timer();
        TimerJob timerJob = new TimerJob();
        TimerJob2 timerJob2 = new TimerJob2();
        timer.schedule(timerJob,3000,2000);
        timer.schedule(timerJob2,5000,3000);
    }
}
/**
运行结果:
Current time:2018-09-18 16:11:08
main
开始执行定时任务=======
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:11
当前线程: Timer-0
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:13
当前线程: Timer-0
当前执行的任务是TimerJob2
Current time : 2018-09-18 16:11:13
当前线程: Timer-0
当前执行的任务是TimerJob
Current time : 2018-09-18 16:11:15
当前线程: Timer-0
当前执行的任务是TimerJob2
Current time : 2018-09-18 16:11:16
当前线程: Timer-0
*/

具体源码分析:

首先分析Timer:
  1. 成员变量

        private final TaskQueue queue = new TaskQueue();
        //该对象是封装了TimerTask的数组,实现类似于list
        /**class TaskQueue {
    	    private TimerTask[] queue = new TimerTask[128];
    	    private int size = 0;
    	    该对象也可以通过他的add方法,进行数组扩容
        */ 
         private final TimerThread thread = new TimerThread(queue);
         //这个线程是等待timerqueue上的task,执行一次任务,重复执行任务,以及移除一些任务
         //这个类很重要,等会具体分析
    
  2. 构造函数

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();//从这儿可以看出,启动了TimerThread线程
    }
  1. 重要方法
 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);
    }
    //此处将delay加上当前时间,获取执行时间
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) {
                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);//将TimerTask的子类放入到TimerQueue中
            if (queue.getMin() == task)
                queue.notify();
        }
    }

好了,上面实现了添加任务,下面就是执行了,我们来分析TimerThread

  1. 大致
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
            //意外杀死了线程,表现的像Timer注销
            synchronized(queue) {
                newTasksMayBeScheduled = false;
                queue.clear();  // Eliminate obsolete references
            }
        }
    }
  1. 具体分析mainLoop方法
 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
                        //如果一直没有task进入数组,die

                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    //获取TimerQueue中最前的task,也就是执行时间最近的
                    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//判断是否要重复执行,不需要直接remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;//更改task状态
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);//更改重复执行的task的下一次的运行时间
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait//如果还没到执行时间,等待
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();//task运行 
                    //,这边使用的是run()而不是start(),也就是说run方法是简单的方法,要按照顺序执行,而不是线程的run方法,在这个地方并没有对run方法进行try/catch
            } catch(InterruptedException e) {
            }
        }
    }

缺陷分析
Timer是单线程
案例:
有两个重复任务(repeat task),task1正常任务,task2会抛出异常,第一个是先执行的,而第二个后执行的,如果正常执行,执行的顺序
task1 ,task1 ,task2,task1 ,task1,。。。,
当执行到task2时,抛出异常,而我们在运行的时候,在TimerThread的mainLoop中的task.run(),我们并没有进行try catch,也就是说,一旦出现异常,我们没有捕获,timer-0这个线程就会终止,而timer有时单线程,也就是会出现程序异常终止。

因为,自己的底子一般般,博文中的一些术语可能使用错误,或者有字打错,望指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值