最近一直在看線程知識,而後看到Timer定時器使用了線程實現的定時功能,因而瞭解瞭解;java
本文 從Time類的使用和源碼分析兩個方面講解:api
2---源碼分析ide
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);
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 }