前言
在我们日常生活中,我们常常会遇到有关计时器的事情。如商城类项目会在某年某月某日某时某分某秒进行特价活动,那么当时间到达这个时间点上的时候该事件就会触发。1、Timer 类构造函数摘要1 Timer()2 创建一个新计时器。3 Timer(boolean isDaemon)4 创建一个新计时器,可以指定其相关的线程作为守护线程运行。5 Timer(String name)6 创建一个新计时器,其相关的线程具有指定的名称7 Timer(String name, boolean isDaemon)8 创建一个新计时器,其相关的线程具有指定的名称,并且可以指定作为守护线程运行2、Timer 类方法摘要1 void cancel()
2 终止此计时器,丢弃所有当前已安排的任务。
3 int purge()
4 从此计时器的任务队列中移除所有已取消的任务。
5 void schedule(TimerTask task, Date time)
6 安排在指定的时间执行指定的任务。
7 void schedule(TimerTask task, Date firstTime, long period)
8 安排指定的任务在指定的时间开始进行重复的固定延迟执行。
9 void schedule(TimerTask task, long delay)
10 安排在指定延迟后执行指定的任务。
11 void schedule(TimerTask task, long delay, long period)
12 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
13 void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
14 安排指定的任务在指定的时间开始进行重复的固定速率执行。
15 void scheduleAtFixedRate(TimerTask task, long delay, long period)
16 安排指定的任务在指定的延迟后开始进行重复的固定速率执行。3、TimerTask 类方法摘要1 boolean cancel()
2 取消此计时器任务。
3 void run()
4 此计时器任务要执行的操作。
5 long scheduledExecutionTime()
6 返回此任务最近实际 执行的已安排 执行时间。4、Timer 源码分析1 package java.util; 2 import dalvik.annotation.optimization.ReachabilitySensitive; 3 import java.util.Date; 4 import java.util.concurrent.atomic.AtomicInteger; 5 6 7 // 定时器类 8 public class Timer { 9 10 // 任务队列 11 @ReachabilitySensitive 12 private final TaskQueue queue = new TaskQueue(); 13 14 // 内置线程 15 @ReachabilitySensitive 16 private final TimerThread thread = new TimerThread(queue); 17 18 /* 19 只是重写了 finalize 方法而已,是为了垃圾回收的时候,将相应的信息回收掉,做 GC 的回补, 20 也就是当 timer 线程由于某种原因死掉了,而未被 cancel,里面的队列中的信息需要清空掉, 21 不过我们通常是不会考虑这个方法的,所以知道 java 写这个方法是干什么的就行了。 22 */ 23 private final Object threadReaper = new Object() { 24 protected void finalize() throws Throwable { 25 synchronized(queue) { 26 thread.newTasksMayBeScheduled = false; 27 queue.notify(); 28 } 29 } 30 }; 31 32 private final static AtomicInteger nextSerialNumber = new AtomicInteger(0); 33 private static int serialNumber() { 34 return nextSerialNumber.getAndIncrement(); 35 } 36 37 // 空的构造函数,这里会调用 Timer(String name) 给相应线程设置默认名称 38 public Timer() { 39 this("Timer-" + serialNumber()); 40 } 41 42 // 是否设置为守护线程并设置默认名称 43 public Timer(boolean isDaemon) { 44 this("Timer-" + serialNumber(), isDaemon); 45 } 46 47 // 给相应线程设置指定名称并开启线程 48 public Timer(String name) { 49 thread.setName(name); 50 thread.start(); 51 } 52 53 // 设置指定名称以及是否设置为守护线程并开启线程 54 public Timer(String name, boolean isDaemon) { 55 thread.setName(name); 56 thread.setDaemon(isDaemon); 57 thread.start(); 58 } 59 60 // 调配任务,设置任务多久后开始 61 public void schedule(TimerTask task, long delay) { 62 if (delay (Long.MAX_VALUE >> 1))110 period >>= 1;111 112 synchronized(queue) {113 if (!thread.newTasksMayBeScheduled)114 throw new IllegalStateException("Timer already cancelled.");115 116 synchronized(task.lock) {117 if (task.state != TimerTask.VIRGIN)118 throw new IllegalStateException("Task already scheduled or cancelled");119 task.nextExecutionTime = time;120 task.period = period;121 task.state = TimerTask.SCHEDULED;122 }123 124 queue.add(task);125 if (queue.getMin() == task)126 queue.notify();127 }128 }129 130 // 中止任务, 一旦执行了这个方法timer就会结束掉131 public void cancel() {132 synchronized(queue) {133 thread.newTasksMayBeScheduled = false;134 queue.clear();135 queue.notify();136 }137 }138 139 // 清除 Timer 中标记为 CANCELLED 的 TimerTask, 返回清除个数140 public int purge() {141 int result = 0;142 143 synchronized(queue) {144 for (int i = queue.size(); i > 0; i--) {145 if (queue.get(i).state == TimerTask.CANCELLED) {146 queue.quickRemove(i);147 result++;148 }149 }150 151 if (result != 0)152 queue.heapify();153 }154 155 return result;156 }157 }158 159 160 // 自定义线程类161 class TimerThread extends Thread {162 163 boolean newTasksMayBeScheduled = true;164 165 private TaskQueue queue;166 167 TimerThread(TaskQueue queue) {168 this.queue = queue;169 }170 171 public void run() {172 try {173 mainLoop();174 } finally {175 synchronized(queue) {176 newTasksMayBeScheduled = false;177 queue.clear();178 }179 }180 }181 182 // 执行任务183 private void mainLoop() {184 while (true) {185 try {186 TimerTask task;187 boolean taskFired;188 synchronized(queue) {189 while (queue.isEmpty() && newTasksMayBeScheduled)190 queue.wait();191 if (queue.isEmpty())192 break;193 194 long currentTime, executionTime;195 task = queue.getMin();196 synchronized(task.lock) {197 if (task.state == TimerTask.CANCELLED) {198 queue.removeMin();199 continue;200 }201 currentTime = System.currentTimeMillis();202 executionTime = task.nextExecutionTime;203 if (taskFired = (executionTime<=currentTime)) {204 if (task.period == 0) { // 区分是否重复执行任务,间隔时间为 0 则执行一次205 queue.removeMin();206 task.state = TimerTask.EXECUTED;207 } else {208 // 区分 schedule 和 scheduleAtFixedRate209 queue.rescheduleMin(210 task.period<0 ? currentTime - task.period211 : executionTime + task.period);212 }213 }214 }215 if (!taskFired) // 下次执行时间大于当前时间 等待216 queue.wait(executionTime - currentTime);217 }218 if (taskFired)219 task.run();220 } catch(InterruptedException e) {221 }222 }223 }224 }225 226 // 自定义任务管理类227 class TaskQueue {228 229 // 初始化 128个空间,实际使用127个 位置编号为0的位置不使用230 private TimerTask[] queue = new TimerTask[128];231 232 private int size = 0;233 234 // 任务队列长度235 int size() {236 return size;237 }238 239 // 添加任务,如果空间不足,空间*2,,然后排序(将nextExecutionTime最小的排到1位置)240 void add(TimerTask task) {241 if (size + 1 == queue.length)242 queue = Arrays.copyOf(queue, 2*queue.length);243 244 queue[++size] = task;245 fixUp(size);246 }247 248 // 得到最小的nextExecutionTime的任务249 TimerTask getMin() {250 return queue[1];251 }252 253 // 得到指定位置的任务254 TimerTask get(int i) {255 return queue[i];256 }257 258 // 删除最小nextExecutionTime的任务,排序(将nextExecutionTime最小的排到1位置)259 void removeMin() {260 queue[1] = queue[size];261 queue[size--] = null;262 fixDown(1);263 }264 265 // 快速删除指定位置的任务266 void quickRemove(int i) {267 assert i <= size;268 269 queue[i] = queue[size];270 queue[size--] = null;271 }272 273 // 重新设置最小nextExecutionTime的任务的nextExecutionTime,排序(将nextExecutionTime最小的排到1位置)274 void rescheduleMin(long newTime) {275 queue[1].nextExecutionTime = newTime;276 fixDown(1);277 }278 279 // 数组是否为空280 boolean isEmpty() {281 return size==0;282 }283 284 // 清空数组285 void clear() {286 for (int i=1; i<=size; i++)287 queue[i] = null;288 289 size = 0;290 }291 292 // 将nextExecutionTime最小的排到1位置293 private void fixUp(int k) {294 while (k > 1) {295 int j = k >> 1;296 if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)297 break;298 TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;299 k = j;300 }301 }302 303 // 将nextExecutionTime最小的排到1位置304 private void fixDown(int k) {305 int j;306 while ((j = k < 0) {307 if (j queue[j+1].nextExecutionTime)308 j++; // j indexes smallest kid309 if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)310 break;311 TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;312 k = j;313 }314 }315 316 // 排序(将nextExecutionTime最小的排到1位置) 在快速删除任务后调用317 void heapify() {318 for (int i = size/2; i >= 1; i--)319 fixDown(i);320 }321 }5、TimerTask 源码1 package java.util; 2 3 4 public abstract class TimerTask implements Runnable { 5 6 final Object lock = new Object(); 7 8 int state = VIRGIN; // 状态 ,未使用,正在使用,非循环,使用完毕 9 10 static final int VIRGIN = 0; // 未使用11 12 static final int SCHEDULED = 1; // 正在循环13 14 static final int EXECUTED = 2; // 非循环15 16 static final int CANCELLED = 3; // 使用完毕17 18 long nextExecutionTime; // 任务执行时间19 20 long period = 0; // 任务循环执行间隔时间21 22 protected TimerTask() {23 }24 25 // 自定义任务26 public abstract void run();27 28 // 退出 任务执行完毕后,退出返回 true ,未执行完 就退出 返回false29 public boolean cancel() {30 synchronized(lock) {31 boolean result = (state == SCHEDULED);32 state = CANCELLED;33 return result;34 }35 }36 37 // 返回 时间38 public long scheduledExecutionTime() {39 synchronized(lock) {40 return (period
Timer:Timer 是一个线程设施,可以用来实现某一个时间或某一段时间后安排某一个任务执行一次或定期重复执行。该功能需要和 TimerTask 类配合使用。每个 Timer 对象对应的是一个线程,因此计时器所执行的任务应该迅速完成,否则会延迟后续的任务执行。
TimerTask:TimerTask 用于实现Timer 类安排的一次或重复执行某个任务,而具体的任务内容在 TimerTask 的 run 方法中去实现。7、Timer 定时器的使用方法1 package cn.pda.serialport; 2 3 import java.util.Calendar; 4 import java.util.Date; 5 import java.util.Timer; 6 import java.util.TimerTask; 7 8 public class TimerTest { 9 10 public static void main(String[] args) {11 // 声明下,这里单位为毫秒,所以 1000 毫秒为 1 秒12 timer1();13 // timer2();14 // timer3();15 // timer4();16 }17 18 // 第一种方法:实现 TimerTask 任务,指定在两秒后执行19 public static void timer1() {20 Timer timer = new Timer();21 timer.schedule(new TimerTask() {22 @Override23 public void run() {24 System.out.println("***** 自定义任务 *****");25 }26 }, 2000);27 }28 29 // 第二种方法:实现 TimerTask 任务,指定在两秒后循环执行,每次执行完后间隔五秒30 public static void timer2() {31 Timer timer = new Timer();32 timer.schedule(new TimerTask() {33 @Override34 public void run() {35 System.out.println("***** 自定义任务 *****");36 }37 }, 2000, 5000);38 }39 40 // 第三种方法:实现 TimerTask 任务,指定在两秒后循环执行,每次执行完后间隔五秒41 public static void timer3() {42 Timer timer = new Timer();43 timer.scheduleAtFixedRate(new TimerTask() {44 @Override45 public void run() {46 System.out.println("***** 自定义任务 *****");47 }48 }, 2000, 5000);49 }50 51 // 第四种方法:实现 TimerTask 任务,指定在某个时间点循环执行,每次执行完间隔二十四小时52 public static void timer4() {53 Calendar calendar = Calendar.getInstance();54 calendar.set(Calendar.HOUR_OF_DAY, 12); // 控制时55 calendar.set(Calendar.MINUTE, 0); // 控制分56 calendar.set(Calendar.SECOND, 0); // 控制秒57 Date time = calendar.getTime(); // 得出执行任务的时间,此处为今天的12:00:0058 Timer timer = new Timer();59 timer.scheduleAtFixedRate(new TimerTask() {60 public void run() {61 System.out.println("***** 自定义任务 *****");62 }63 }, time, 1000 * 60 * 60 * 24);// 这里设定将延时每天固定执行64 }65 66 }