Wednesday, December 30, 2020

Java 定时调配 Timer 类和定任务 TimerTask 类

前言

        在我们日常生活中,我们常常会遇到有关计时器的事情。如商城类项目会在某年某月某日某时某分某秒进行特价活动,那么当时间到达这个时间点上的时候该事件就会触发。

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 < 0) 63    throw new IllegalArgumentException("Negative delay."); 64   sched(task, System.currentTimeMillis()+delay, 0); 65  } 66  67  // 调配任务,设置任务什么时候开始 68  public void schedule(TimerTask task, Date time) { 69   sched(task, time.getTime(), 0); 70  } 71  72  // 调配任务,设置任务多久后开始循环执行并间隔多久 73  public void schedule(TimerTask task, long delay, long period) { 74   if (delay < 0) 75    throw new IllegalArgumentException("Negative delay."); 76   if (period <= 0) 77    throw new IllegalArgumentException("Non-positive period."); 78   sched(task, System.currentTimeMillis()+delay, -period); 79  } 80  81  // 调配任务,设置任务循环执行时间并间隔多久 82  public void schedule(TimerTask task, Date firstTime, long period) { 83   if (period <= 0) 84    throw new IllegalArgumentException("Non-positive period."); 85   sched(task, firstTime.getTime(), -period); 86  } 87  88  // 调配任务,设置任务多久后开始循环执行并间隔多久 89  public void scheduleAtFixedRate(TimerTask task, long delay, long period) { 90   if (delay < 0) 91    throw new IllegalArgumentException("Negative delay."); 92   if (period <= 0) 93    throw new IllegalArgumentException("Non-positive period."); 94   sched(task, System.currentTimeMillis()+delay, period); 95  } 96  97  // 调配任务,设置任务循环执行时间并间隔多久 98  public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) { 99   if (period <= 0)100    throw new IllegalArgumentException("Non-positive period.");101   sched(task, firstTime.getTime(), period);102  }103 104  // 任务调配105  private void sched(TimerTask task, long time, long period) {106   if (time < 0)107    throw new IllegalArgumentException("Illegal execution time.");108 109   if (Math.abs(period) > (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 << 1) <= size && j > 0) {307    if (j < size && queue[j].nextExecutionTime > 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 < 0 ? nextExecutionTime + period41      : nextExecutionTime - period);42   }43  }44 }

6、Timer 与 TimerTask

        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 }

 









原文转载:http://www.shaoqun.com/a/504544.html

跨境电商:https://www.ikjzd.com/

跨境通电子商务平台:https://www.ikjzd.com/w/1329.html

cima:https://www.ikjzd.com/w/1372


前言在我们日常生活中,我们常常会遇到有关计时器的事情。如商城类项目会在某年某月某日某时某分某秒进行特价活动,那么当时间到达这个时间点上的时候该事件就会触发。1、Timer类构造函数摘要1Timer()2创建一个新计时器。3Timer(booleanisDaemon)4创建一个新计时器,可以指定其相关的线程作为守护线程运行。5Timer(Stringname)6创建一个新计时器,其相关的线程具有指定
浩方:浩方
houzz:houzz
德庆盘龙峡薰衣草木屋住宿?德庆盘龙峡住宿方便吗?:德庆盘龙峡薰衣草木屋住宿?德庆盘龙峡住宿方便吗?
国庆去巴塞罗那旅游的注意事项:国庆去巴塞罗那旅游的注意事项
第17号台风"塔巴"减弱即将被停编 韩国日本局地仍暴雨:第17号台风"塔巴"减弱即将被停编 韩国日本局地仍暴雨

No comments:

Post a Comment