java之 Timer 類的使用以及深刻理解

 

最近一直在看線程知識,而後看到Timer定時器使用了線程實現的定時功能,因而瞭解瞭解;java

本文 從Time類的使用和源碼分析兩個方面講解:api

1---Timer類使用數組

2---源碼分析ide

一、Time類使用:oop

     

 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)

 

示例:源碼分析

只執行一次:ui

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

循環執行:this

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

 

二、源碼分析:atom

 

Timer 源碼:spa


程序運行:

在初始化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 }
相關文章
相關標籤/搜索