java之 Timer 类的使用以及深入理解

 

最近一直在看线程知识,然后看到Timer定时器使用了线程实现的定时功能,于是了解了解;

本文 从Time类的使用和源码分析两个方面讲解:

1---Timer类使用

2---源码分析

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 }

 

posted @ 2017-05-18 17:49  小淘气儿  阅读(46506)  评论(0编辑  收藏  举报