java之 Timer 类的使用以及深入理解
最近一直在看线程知识,然后看到Timer定时器使用了线程实现的定时功能,于是了解了解;
本文 从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);
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 }