次数啥的,不过等会就知道是什么了;另外关于方法: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