zoukankan      html  css  js  c++  java
  • java之 Timer 类的使用以及深入理解

    最近一直在看线程知识,然后看到Timer定时器使用了线程实现的定时功能,于是了解了解;

    本文 从Time类的使用和源码分析两个方面讲解:

    1---Timer类使用

    2---源码分析

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

    2、源码分析:

    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 }
  • 相关阅读:
    Android状态栏白底黑字,只需两步轻松搞定
    MyBatis注解
    MyBatis延迟加载和缓存
    MyBatis关联查询
    mybatis智能标签1
    Mybatis智能标签
    增删改查
    初始MyBatis
    第7章:Servlet 基础
    第3章 JSP数据交互(二)
  • 原文地址:https://www.cnblogs.com/xiaotaoqi/p/6874713.html
Copyright © 2011-2022 走看看