设为首页 加入收藏

TOP

Java Timer(定时调用、实现固定时间执行)(二)
2015-08-31 21:24:03 来源: 作者: 【 】 浏览:77
Tags:Java Timer 定时 调用 实现 固定 时间 执行
次数啥的,不过等会就知道是什么了;另外关于方法:sched的内容我们不着急去看他,先看下重载的方法中是如何做的


  再看看方法:


public void schedule(TimerTask task, long delay,long period)


?  源码为:


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);
? ? }


?  看来也调用了方法sched来完成调度,和上面的方法唯一的调度时候的区别是增加了传入的period,而第一个传入的是0,所以确定这个参数为时间片, 而不是次数,注意这个里的period加了一个负数,也就是取反,也就是我们开始传入1000,在调用sched的时候会变成-1000,其实最终阅读完 源码后你会发现这个算是老外对于一种数字的理解,而并非有什么特殊的意义,所以阅读源码的时候也有这些困难所在。


  最后再看个方法是:


public void scheduleAtFixedRate(TimerTasktask,long delay,long 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);
? }


?  唯一的区别就是在period没有取反,其实你最终阅读完源码,上面的取反没有什么特殊的意义,老外不想增加一个参数来表示 scheduleAtFixedRate,而scheduleAtFixedRate和schedule的大部分逻辑代码一致,因此用了参数的范围来作为 区分方法,也就是当你传入的参数不是正数的时候,你调用schedule方法正好是得到scheduleAtFixedRate的功能,而调用 scheduleAtFixedRate方法的时候得到的正好是schedule方法的功能,呵呵,这些讨论没什么意义,讨论实质和重点:


?  来看sched方法的实现体:


private void sched(TimerTask task, long time, long period) {
? ? ? ? if (time < 0)
? ? ? ? ? ? throw new IllegalArgumentException("Illegal execution time.");
?
? ? ? ? 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);
? ? ? ? ? ? if (queue.getMin() == task)
? ? ? ? ? ? ? ? queue.notify();
? ? ? ? }
? ? }


?  queue为一个队列,我们先不看他数据结构,看到他在做这个操作的时候,发生了同步,所以在timer级别,这个是线程安全的,最后将task相关的参数赋值,主要包含nextExecutionTime(下一次执行时间),period(时间片),state(状态),然后将它放入queue队列中,做一次notify操作,为什么要做notify操作呢?看了后面的代码你就知道了。


  简言之,这里就是讲task放入队列queue的过程,此时,你可能对queue的结构有些兴趣,那么我们先来看看queue属性的结构TaskQueue:


class TaskQueue {
?
? ? private TimerTask[] queue = new TimerTask[128];
?
? ? private int size = 0;


?  可见,TaskQueue的结构很简单,为一个数组,加一个size,有点像ArrayList,是不是长度就128呢,当然不 是,ArrayList可以扩容,它可以,只是会造成内存拷贝而已,所以一个Timer来讲,只要内部的task个数不超过128是不会造成扩容的;内部 提供了add(TimerTask)、size()、getMin()、get(int)、removeMin()、quickRemove(int)、 rescheduleMin(long newTime)、isEmpty()、clear()、fixUp()、fixDown()、heapify();


   


--------------------------------------------------------------------------------


实践部分:


1、通过继承TimerTask的方式实现


  必须重写run方法.


public class MyTask extends TimerTask
{


? ? @Override
? ? public void run()
? ? {
? ? ? ? SimpleDateFormat sdf = null;
? ? ? ? sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
? ? ? ? System.out.println("当前时间:" + sdf.format(new Date()));
? ? ? ?
? ? }
? ?
}


public class TestTask
{
? ? public static void main(String[] args)
? ? {
? ? ? ? Timer t = new Timer(); // 建立Timer对象
? ? ? ? MyTask task = new MyTask(); //定义任务
? ? ? ? t.schedule(task, 1000,2000);//设置任务的执行,1秒后开始,每2秒执行一次
? ? ? ?
? ? ? ? Calendar cal = Calendar.getInstance();
? ? ? ? cal.set(Calendar.MINUTE, 30

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Spring 容器加载完成后执行某个方.. 下一篇PHP的MySQLi函数库的使用 及 表单..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: