近一直在看线程知识,然后看到Timer定时器使用了线程实现的定时功能,于是了解了解;
  本文 从Time类的使用和源码分析两个方面讲解:
  1、Time类使用:
1  根据是否循环执行分为两类:
2
3         //只执行一次
4         public void schedule(TimerTask task, long delay);
5         public void schedule(TimerTask task, Date time);
6
7         //循环执行
8         // 在循环执行类别中根据循环时间间隔又可以分为两类
9         public void schedule(TimerTask task, long delay, long period) ;
10         public void schedule(TimerTask task, Date firstTime, long period) ;
11
12
13         public void scheduleAtFixedRate(TimerTask task, long delay, long period)
14         public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
  示例:
  只执行一次:
1         Timer timer = new Timer();
2
3         //延迟1000ms执行程序
4         timer.schedule(new TimerTask() {
5             @Override
6             public void run() {
7                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
8             }
9         }, 1000);
10         //延迟10000ms执行程序
11         timer.schedule(new TimerTask() {
12             @Override
13             public void run() {
14                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
15             }
16         }, new Date(System.currentTimeMillis() + 10000));
  循环执行:
1         Timer timer = new Timer();
2
3         //前一次执行程序结束后 2000ms 后开始执行下一次程序
4         timer.schedule(new TimerTask() {
5             @Override
6             public void run() {
7                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
8             }
9         }, 0,2000);
10
11         //前一次程序执行开始 后 2000ms后开始执行下一次程序
12         timer.scheduleAtFixedRate(new TimerTask() {
13             @Override
14             public void run() {
15                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
16             }
17         },0,2000);
  2、源码分析:
  Timer 源码:
  程序运行:
  在初始化Timer时 ,开启一个线程循环提取任务数组中的任务,如果任务数组为空,线程等待直到添加任务;
  当添加任务时,唤醒线程,提取数组中标记为1的任务,
  如果该任务状态为CANCELLED,则从数组中删除任务,continue ,继续循环提取任务;
  然后将当前时间与任务执行时间点比较 标记 taskFired=executionTime<=currentTime;
  taskFired =false ,说明任务执行时间还没到,则调用wait等待( executionTime- currentTime ) 时间长度,然后循环重新提取该任务;
  taskFired =true,说明任务执行时间已经到了,或者过去了。继续判断 任务循环时间间隔period;
  period=0时,说明此次任务是非循环任务,直接将该任务从数组中删除,并将状态置为 EXECUTED,然后执行任务的run方法!
  period!=0时,说明此次任务时循环任务,将该任务的执行时间点向前推进,具体推进时间根据调用的方法判断;
  如果是schedule方法,则在当前时间基础上向前推进period时间长度;
  如果是scheduleAtFixedRate方法,则在当前任务执行时间点基础上向前推进period时间长度,
  后执行任务的run方法;循环提取任务
1 package java.util;
2 import java.util.Date;
3 import java.util.concurrent.atomic.AtomicInteger;
4
5
6 public class Timer {
7
8     private final TaskQueue queue = new TaskQueue();
9
10
11     private final TimerThread thread = new TimerThread(queue);
12
13
14     private final Object threadReaper = new Object() {
15         protected void finalize() throws Throwable {
16             synchronized(queue) {
17                 thread.newTasksMayBeScheduled = false;
18                 queue.notify(); // In case queue is empty.
19             }
20         }
21     };
22
23
24     private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
25     private static int serialNumber() {
26         return nextSerialNumber.getAndIncrement();
27     }
28
29
30     public Timer() {
31         this("Timer-" + serialNumber());
32     }
33
34
35     public Timer(boolean isDaemon) {
36         this("Timer-" + serialNumber(), isDaemon);
37     }
38
39
40     public Timer(String name) {
41         thread.setName(name);
42         thread.start();
43     }
44
45     //在初始化Timer时,确定线程名称,以及是否是守护线程 ,开启线程
46     public Timer(String name, boolean isDaemon) {
47         thread.setName(name);
48         thread.setDaemon(isDaemon);
49         thread.start();
50     }
51
52
53     public void schedule(TimerTask task, long delay) {
54         if (delay < 0)
55             throw new IllegalArgumentException("Negative delay.");
56         sched(task, System.currentTimeMillis()+delay, 0);
57     }
58
59
60     public void schedule(TimerTask task, Date time) {
61         sched(task, time.getTime(), 0);
62     }
63
64
65     public void schedule(TimerTask task, long delay, long period) {
66         if (delay < 0)
67             throw new IllegalArgumentException("Negative delay.");
68         if (period <= 0)
69             throw new IllegalArgumentException("Non-positive period.");
70         sched(task, System.currentTimeMillis()+delay, -period);
71     }
72
73
74     public void schedule(TimerTask task, Date firstTime, long period) {
75         if (period <= 0)
76             throw new IllegalArgumentException("Non-positive period.");
77         sched(task, firstTime.getTime(), -period);
78     }
79
80
81     public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
82         if (delay < 0)
83             throw new IllegalArgumentException("Negative delay.");
84         if (period <= 0)
85             throw new IllegalArgumentException("Non-positive period.");
86         sched(task, System.currentTimeMillis()+delay, period);
87     }
88
89
90     public void scheduleAtFixedRate(TimerTask task, Date firstTime,
91                                     long period) {
92         if (period <= 0)
93             throw new IllegalArgumentException("Non-positive period.");
94         sched(task, firstTime.getTime(), period);
95     }
96
97
98     private void sched(TimerTask task, long time, long period) {
99         if (time < 0)
100             throw new IllegalArgumentException("Illegal execution time.");
101
102         // Constrain value of period sufficiently to prevent numeric
103         // overflow while still being effectively infinitely large.
104         if (Math.abs(period) > (Long.MAX_VALUE >> 1))
105             period >>= 1;
106
107         synchronized(queue) {
108             if (!thread.newTasksMayBeScheduled)
109                 throw new IllegalStateException("Timer already cancelled.");
110
111             synchronized(task.lock) {
112                 if (task.state != TimerTask.VIRGIN)
113                     throw new IllegalStateException(
114                         "Task already scheduled or cancelled");
115                 task.nextExecutionTime = time;
116                 task.period = period;
117                 task.state = TimerTask.SCHEDULED;
118             }
119
120             queue.add(task);
121             if (queue.getMin() == task)
122                 queue.notify();
123         }
124     }
125
126
127     public void cancel() {
128         synchronized(queue) {
129             thread.newTasksMayBeScheduled = false;
130             queue.clear();
131             queue.notify();  // In case queue was already empty.
132         }
133     }
134
135     //净化,清除timer中标记为CANCELLED的TIMETASK,  返回值为清除个数
136      public int purge() {
137          int result = 0;
138
139          synchronized(queue) {
140              for (int i = queue.size(); i > 0; i--) {
141                  if (queue.get(i).state == TimerTask.CANCELLED) {
142                      queue.quickRemove(i);
143                      result++;
144                  }
145              }
146
147              if (result != 0)
148                  queue.heapify();
149          }
150
151          return result;
152      }
153 }
154
155 //自定义线程
156 class TimerThread extends Thread {
157
158     boolean newTasksMayBeScheduled = true;
159
160
161     private TaskQueue queue;
162
163     TimerThread(TaskQueue queue) {
164         this.queue = queue;
165     }
166
167     public void run() {
168         try {
169             mainLoop();
170         } finally {
171             // Someone killed this Thread, behave as if Timer cancelled
172             synchronized(queue) {
173                 newTasksMayBeScheduled = false;
174                 queue.clear();  // Eliminate obsolete references
175             }
176         }
177     }
178
179
180     private void mainLoop() {
181         while (true) {
182             try {
183                 TimerTask task;
184                 boolean taskFired;
185                 synchronized(queue) {
186                     // Wait for queue to become non-empty
187                     while (queue.isEmpty() && newTasksMayBeScheduled)
188                         queue.wait();
189                     if (queue.isEmpty())
190                         break; // Queue is empty and will forever remain; die
191
192                     // Queue nonempty; look at first evt and do the right thing
193                     long currentTime, executionTime;
194                     task = queue.getMin();
195                     synchronized(task.lock) {
196                         if (task.state == TimerTask.CANCELLED) {//移除 状态为已执行完毕的任务
197                             queue.removeMin();
198                             continue;
199                         }
200                         currentTime = System.currentTimeMillis();
201                         executionTime = task.nextExecutionTime;
202                         if (taskFired = (executionTime<=currentTime)) {
203                             if (task.period == 0) { // 循环条件为0时,直接清除任务,并将任务状态置为非循环任务,并执行一次任务!
204                                 queue.removeMin();
205                                 task.state = TimerTask.EXECUTED;
206                             } else { //区分  两种循环类别的关键
207                                 queue.rescheduleMin(
208                                   task.period<0 ? currentTime   - task.period
209                                                 : executionTime + task.period);
210                             }
211                         }
212                     }
213                     if (!taskFired) // 当下次执行任务时间大于当前时间  等待
214                         queue.wait(executionTime - currentTime);
215                 }
216                 if (taskFired)  // 执行任务
217                     task.run();
218             } catch(InterruptedException e) {
219             }
220         }
221     }
222 }
223
224 /**
225  *
226  * 任务管理内部类
227  */
228 class TaskQueue {
229
230     //初始化  128个空间,实际使用127个  位置编号为0的位置不使用
231     private TimerTask[] queue = new TimerTask[128];
232
233
234     private int size = 0;
235
236
237     int size() {
238         return size;
239     }
240
241     //添加任务,如果空间不足,空间*2,,然后排序(将nextExecutionTime小的排到1位置)
242     void add(TimerTask task) {
243         // Grow backing store if necessary
244         if (size + 1 == queue.length)
245             queue = Arrays.copyOf(queue, 2*queue.length);
246
247         queue[++size] = task;
248         fixUp(size);
249     }
250
251     //得到小的nextExecutionTime的任务
252     TimerTask getMin() {
253         return queue[1];
254     }
255
256     //得到指定位置的任务
257     TimerTask get(int i) {
258         return queue[i];
259     }
260
261     //删除小nextExecutionTime的任务,排序(将nextExecutionTime小的排到1位置)
262     void removeMin() {
263         queue[1] = queue[size];
264         queue[size--] = null;  // Drop extra reference to prevent memory leak
265         fixDown(1);
266     }
267
268     //快速删除指定位置的任务
269     void quickRemove(int i) {
270         assert i <= size;
271
272         queue[i] = queue[size];
273         queue[size--] = null;  // Drop extra ref to prevent memory leak
274     }
275
276     //重新设置小nextExecutionTime的任务的nextExecutionTime,排序(将nextExecutionTime小的排到1位置)
277     void rescheduleMin(long newTime) {
278         queue[1].nextExecutionTime = newTime;
279         fixDown(1);
280     }
281
282     //数组是否为空
283     boolean isEmpty() {
284         return size==0;
285     }
286
287    //清空数组
288     void clear() {
289         // Null out task references to prevent memory leak
290         for (int i=1; i<=size; i++)
291             queue[i] = null;
292
293         size = 0;
294     }
295
296     //将nextExecutionTime小的排到1位置
297     private void fixUp(int k) {
298         while (k > 1) {
299             int j = k >> 1;
300             if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
301                 break;
302             TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
303             k = j;
304         }
305     }
306
307     //将nextExecutionTime小的排到1位置
308     private void fixDown(int k) {
309         int j;
310         while ((j = k << 1) <= size && j > 0) {
311             if (j < size &&
312                 queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
313                 j++; // j indexes smallest kid
314             if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
315                 break;
316             TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
317             k = j;
318         }
319     }
320
321      //排序(将nextExecutionTime小的排到1位置)   在快速删除任务后调用
322     void heapify() {
323         for (int i = size/2; i >= 1; i--)
324             fixDown(i);
325     }
326 }
  TimerTask源码:
  功能:用户任务,Timer执行任务实体(任务状态,任务下次执行时间点,任务循环时间间隔,任务本体【run】)
1 package java.util;
2 /**
3  * 虽然实现了Runnable接口 但是在Timer中直接调用run方法,
4  * */
5 public abstract class TimerTask implements Runnable {
6
7     final Object lock = new Object();
8
9     int state = VIRGIN;  //状态 ,未使用,正在使用,非循环,使用完毕
10
11
12     static final int VIRGIN = 0; //未使用
13
14     static final int SCHEDULED   = 1;//正在使用
15
16
17     static final int EXECUTED    = 2;//非循环
18
19
20     static final int CANCELLED   = 3;//使用完毕
21
22
23     long nextExecutionTime;  //下载调用任务时间
24
25
26     long period = 0;// 循环时间间隔
27
28     protected TimerTask() {
29     }
30
31
32     public abstract void run();//自定义任务
33
34     //退出   任务执行完毕后,退出返回 true ,未执行完 退出 返回false
35     public boolean cancel() {
36         synchronized(lock) {
37             boolean result = (state == SCHEDULED);
38             state = CANCELLED;
39             return result;
40         }
41     }
42     //返回 时间
43     public long scheduledExecutionTime() {
44         synchronized(lock) {
45             return (period < 0 ? nextExecutionTime + period
46                                : nextExecutionTime - period);
47         }
48     }
49 }  近一直在看线程知识,然后看到Timer定时器使用了线程实现的定时功能,于是了解了解;
  本文 从Time类的使用和源码分析两个方面讲解:
  1、Time类使用:
1  根据是否循环执行分为两类:
2
3         //只执行一次
4         public void schedule(TimerTask task, long delay);
5         public void schedule(TimerTask task, Date time);
6
7         //循环执行
8         // 在循环执行类别中根据循环时间间隔又可以分为两类
9         public void schedule(TimerTask task, long delay, long period) ;
10         public void schedule(TimerTask task, Date firstTime, long period) ;
11
12
13         public void scheduleAtFixedRate(TimerTask task, long delay, long period)
14         public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
  示例:
  只执行一次:
1         Timer timer = new Timer();
2
3         //延迟1000ms执行程序
4         timer.schedule(new TimerTask() {
5             @Override
6             public void run() {
7                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
8             }
9         }, 1000);
10         //延迟10000ms执行程序
11         timer.schedule(new TimerTask() {
12             @Override
13             public void run() {
14                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
15             }
16         }, new Date(System.currentTimeMillis() + 10000));
  循环执行:
1         Timer timer = new Timer();
2
3         //前一次执行程序结束后 2000ms 后开始执行下一次程序
4         timer.schedule(new TimerTask() {
5             @Override
6             public void run() {
7                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
8             }
9         }, 0,2000);
10
11         //前一次程序执行开始 后 2000ms后开始执行下一次程序
12         timer.scheduleAtFixedRate(new TimerTask() {
13             @Override
14             public void run() {
15                 System.out.println("IMP 当前时间" + this.scheduledExecutionTime());
16             }
17         },0,2000);
  2、源码分析:
  Timer 源码:
  程序运行:
  在初始化Timer时 ,开启一个线程循环提取任务数组中的任务,如果任务数组为空,线程等待直到添加任务;
  当添加任务时,唤醒线程,提取数组中标记为1的任务,
  如果该任务状态为CANCELLED,则从数组中删除任务,continue ,继续循环提取任务;
  然后将当前时间与任务执行时间点比较 标记 taskFired=executionTime<=currentTime;
  taskFired =false ,说明任务执行时间还没到,则调用wait等待( executionTime- currentTime ) 时间长度,然后循环重新提取该任务;
  taskFired =true,说明任务执行时间已经到了,或者过去了。继续判断 任务循环时间间隔period;
  period=0时,说明此次任务是非循环任务,直接将该任务从数组中删除,并将状态置为 EXECUTED,然后执行任务的run方法!
  period!=0时,说明此次任务时循环任务,将该任务的执行时间点向前推进,具体推进时间根据调用的方法判断;
  如果是schedule方法,则在当前时间基础上向前推进period时间长度;
  如果是scheduleAtFixedRate方法,则在当前任务执行时间点基础上向前推进period时间长度,
  后执行任务的run方法;循环提取任务
1 package java.util;
2 import java.util.Date;
3 import java.util.concurrent.atomic.AtomicInteger;
4
5
6 public class Timer {
7
8     private final TaskQueue queue = new TaskQueue();
9
10
11     private final TimerThread thread = new TimerThread(queue);
12
13
14     private final Object threadReaper = new Object() {
15         protected void finalize() throws Throwable {
16             synchronized(queue) {
17                 thread.newTasksMayBeScheduled = false;
18                 queue.notify(); // In case queue is empty.
19             }
20         }
21     };
22
23
24     private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
25     private static int serialNumber() {
26         return nextSerialNumber.getAndIncrement();
27     }
28
29
30     public Timer() {
31         this("Timer-" + serialNumber());
32     }
33
34
35     public Timer(boolean isDaemon) {
36         this("Timer-" + serialNumber(), isDaemon);
37     }
38
39
40     public Timer(String name) {
41         thread.setName(name);
42         thread.start();
43     }
44
45     //在初始化Timer时,确定线程名称,以及是否是守护线程 ,开启线程
46     public Timer(String name, boolean isDaemon) {
47         thread.setName(name);
48         thread.setDaemon(isDaemon);
49         thread.start();
50     }
51
52
53     public void schedule(TimerTask task, long delay) {
54         if (delay < 0)
55             throw new IllegalArgumentException("Negative delay.");
56         sched(task, System.currentTimeMillis()+delay, 0);
57     }