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


ScheduledThreadPoolExecutor类的overflowFree方法overflowFree方法的源代码如下所示:
private long overflowFree(long delay) { //获取队列中的节点 Delayed head = (Delayed) super.getQueue().peek(); //获取的节点不为空 , 则进行后续处理 if (head != null) {  //从队列节点中获取延迟时间  long headDelay = head.getDelay(NANOSECONDS);  //如果从队列中获取的延迟时间小于0 , 并且传递的delay  //值减去从队列节点中获取延迟时间小于0  if (headDelay < 0 && (delay - headDelay < 0))   //将delay的值设置为Long.MAX_VALUE + headDelay   delay = Long.MAX_VALUE + headDelay; } //返回延迟时间 return delay;}通过对overflowFree方法的源码分析 , 可以看出overflowFree方法本质上就是为了限制队列中的所有节点的延迟时间在Long.MAX_VALUE值之内 , 防止在compareTo方法中溢出 。
cancel方法cancel方法的作用主要是取消当前任务的执行 , 源码如下所示:
public boolean cancel(boolean mayInterruptIfRunning) { //取消任务 , 返回任务是否取消的标识 boolean cancelled = super.cancel(mayInterruptIfRunning); //如果任务已经取消 //并且需要将任务从延迟队列中删除 //并且任务在延迟队列中的索引大于或者等于0 if (cancelled && removeOnCancel && heapIndex >= 0)  //将当前任务从延迟队列中删除  remove(this); //返回是否成功取消任务的标识 return cancelled;}这段代码理解起来相对比较简单 , 首先调用取消任务的方法 , 并返回任务是否已经取消的标识 。如果任务已经取消 , 并且需要移除任务 , 同时 , 任务在延迟队列中的索引大于或者等于0 , 则将当前任务从延迟队列中移除 。最后返回任务是否成功取消的标识 。
run方法run方法可以说是ScheduledFutureTask类的核心方法 , 是对Runnable接口的实现 , 源码如下所示:
public void run() { //当前任务是否是周期性任务 boolean periodic = isPeriodic(); //线程池当前运行状态下不能执行周期性任务 if (!canRunInCurrentRunState(periodic))  //取消任务的执行  cancel(false); //如果不是周期性任务 else if (!periodic)  //则直接调用FutureTask类的run方法执行任务  ScheduledFutureTask.super.run(); //如果是周期性任务 , 则调用FutureTask类的runAndReset方法执行任务 //如果任务执行成功 else if (ScheduledFutureTask.super.runAndReset()) {  //设置下次执行任务的时间  setNextRunTime();  //重复执行任务  reExecutePeriodic(outerTask); }}整理一下方法的逻辑:

  1. 首先判断当前任务是否是周期性任务 。如果线程池当前运行状态下不能执行周期性任务 , 则取消任务的执行 , 否则执行步骤2;
  2. 如果当前任务不是周期性任务 , 则直接调用FutureTask类的run方法执行任务 , 会设置执行结果 , 然后直接返回 , 否则执行步骤3;
  3. 如果当前任务是周期性任务 , 则调用FutureTask类的runAndReset方法执行任务 , 不会设置执行结果 , 然后直接返回 , 否则执行步骤4;
  4. 如果任务执行成功 , 则设置下次执行任务的时间 , 同时 , 将任务设置为重复执行 。
这里 , 调用了FutureTask类的run方法和runAndReset方法 , 并且调用了ScheduledThreadPoolExecutor类的reExecutePeriodic方法 。接下来 , 我们分别看下这些方法的实现 。
FutureTask类的run方法FutureTask类的run方法源码如下所示:
public void run() {    //状态如果不是NEW , 说明任务或者已经执行过 , 或者已经被取消 , 直接返回    //状态如果是NEW , 则尝试把当前执行线程保存在runner字段中    //如果赋值失败则直接返回    if (state != NEW ||        !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))        return;    try {        Callable<V> c = callable;        if (c != null && state == NEW) {            V result;            boolean ran;            try {                //执行任务                result = c.call();                ran = true;            } catch (Throwable ex) {                result = null;                ran = false;                //任务异常                setException(ex);            }            if (ran)                //任务正常执行完毕                set(result);        }    } finally {        runner = null;        int s = state;        //如果任务被中断 , 执行中断处理        if (s >= INTERRUPTING)            handlePossibleCancellationInterrupt(s);    }}


推荐阅读