并发编程之定时任务&定时线程池原理解析( 四 )

通过源码可以看到 , 在ScheduledFutureTask类的构造方法中 , 首先会调用FutureTask类的构造方法为FutureTask类的callable和state成员变量赋值 , 接下来为ScheduledFutureTask类的time、period和sequenceNumber成员变量赋值 。理解起来比较简单 。
getDelay方法我们先来看getDelay方法的源码 , 如下所示:
//获取下次执行任务的时间距离当前时间的纳秒数public long getDelay(TimeUnit unit) { return unit.convert(time - now(), NANOSECONDS);}getDelay方法比较简单 , 主要用来获取下次执行任务的时间距离当前系统时间的纳秒数 。
compareTo方法ScheduledFutureTask类在类的结构上实现了Comparable接口 , compareTo方法主要是对Comparable接口定义的compareTo方法的实现 。源码如下所示:
public int compareTo(Delayed other) { if (other == this)   return 0; if (other instanceof ScheduledFutureTask) {  ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;  long diff = time - x.time;  if (diff < 0)   return -1;  else if (diff > 0)   return 1;  else if (sequenceNumber < x.sequenceNumber)   return -1;  else   return 1; } long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS); return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;}这段代码看上去好像是对各种数值类型数据的比较 , 本质上是对延迟队列中的任务进行排序 。排序规则为:

  • 首先比较延迟队列中每个任务下次执行的时间 , 下次执行时间距离当前时间短的任务会排在前面;
  • 如果下次执行任务的时间相同 , 则会比较任务的sequenceNumber值 , sequenceNumber值小的任务会排在前面 。
isPeriodic方法isPeriodic方法的源代码如下所示:
//判断是否是周期性任务public boolean isPeriodic() { return period != 0;}这个方法主要是用来判断当前任务是否是周期性任务 。这里只要判断运行任务的执行周期不等于0就能确定为周期性任务了 。因为无论period的值是大于0还是小于0 , 当前任务都是周期性任务 。
setNextRunTime方法setNextRunTime方法的作用主要是设置当前任务下次执行的时间 , 源码如下所示:
private void setNextRunTime() { long p = period; //固定频率 , 上次执行任务的时间加上任务的执行周期 if (p > 0)  time += p; //相对固定的延迟执行 , 当前系统时间加上任务的执行周期 else  time = triggerTime(-p);}这里再一次证明了使用isPeriodic方法判断当前任务是否为周期性任务时 , 只要判断period的值是否不等于0就可以了 。
  • 因为如果当前任务时固定频率执行的周期性任务 , 会将周期period当作正数来处理;
  • 如果是相对固定的延迟执行当前任务 , 则会将周期period当作负数来处理 。
这里我们看到在setNextRunTime方法中 , 调用了ScheduledThreadPoolExecutor类的triggerTime方法 。接下来我们看下triggerTime方法的源码 。
ScheduledThreadPoolExecutor类的triggerTime方法triggerTime方法用于获取延迟队列中的任务下一次执行的具体时间 。源码如下所示 。
private long triggerTime(long delay, TimeUnit unit) { return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));}long triggerTime(long delay) { return now() +  ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));}这两个triggerTime方法的代码比较简单 , 就是获取下一次执行任务的具体时间 。有一点需要注意的是:delay < (Long.MAX_VALUE >> 1判断delay的值是否小于Long.MAX_VALUE的一半 , 如果小于Long.MAX_VALUE值的一半 , 则直接返回delay , 否则需要处理溢出的情况 。
我们看到在triggerTime方法中处理防止溢出的逻辑使用了ScheduledThreadPoolExecutor类的overflowFree方法 , 接下来 , 我们就看看ScheduledThreadPoolExecutor类的overflowFree方法的实现 。


推荐阅读