3.实现了RunnableScheduledFuture接口,其主要方法isPeriodic()用于判断是不是周期任务,又继承了RunnableFuture接口.
4.ScheduledFutureTask又继承了FutureTask类,而FutureTask类实现了RunnableFuture接口 。(故感觉RunnableFuture接口的那些方法挺重要的)
5.RunnableFuture接口主要是由Runnable和Future两大接口组成(自己去看继承关系),主要有run()方法 。
2.ScheduledFutureTask类#run方法
代码展示
// 重写FutureTask,如果是周期性任务需要重新放入队列public void run() {// 检查当前状态 不能执行任务 , 则取消任务if (!canRunInCurrentRunState(this))cancel(false);//如果不是周期任务,调用FutureTask.run()执行任务(非周期任务直接执行)else if (!isPeriodic())super.run();// 周期性任务else if (super.runAndReset()) {//与run方法的不同就是正常完成后任务的状态不会变化,依旧是NEW,且返回值为成功或失败,不会设置result属性setNextRunTime(); //设置任务下次执行时间reExecutePeriodic(outerTask);}}代码说明
1.这里面很明显存在一个隐患,那就是没有捕捉异常 , 所以如果我们自定义的run()方法中如果没有捕捉异常的话,那么出现异常的时候我们容易两眼摸瞎 。
2.故使用定时任务的时候,自定义的run方法需要自行捕捉异常进行处理 。
3.ScheduledFutureTask类#setNextRunTime方法
代码展示
//判断指定的任务是否为定期任务private void setNextRunTime() {long p = period; //取出周期时间if (p > 0)time += p; //time是周期任务的下一次执行时间elsetime = triggerTime(-p);}// ScheduledThreadPoolExecutor中的方法long triggerTime(long delay) {//delay 的值是否小于 Long.MAX_VALUE 的一半,是的话,当前时间+延迟时间return System.nanoTime() + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));}// ScheduledThreadPoolExecutor中的方法private long overflowFree(long delay) {//获取队列中的首节点Delayed head = (Delayed) super.getQueue().peek();//获取的节点不为空,则进行后续处理if (head != null) {//从队列节点中获取延迟时间long headDelay = head.getDelay(NANOSECONDS);//如果从队列中获取的延迟时间小于0,并且传递的delay值减去从队列节点中获取延迟时间小于0if (headDelay < 0 && (delay - headDelay < 0))//将delay的值设置为Long.MAX_VALUE + headDelay(该数字为负数)delay = Long.MAX_VALUE + headDelay;}//返回延迟时间return delay;}代码说明
1.周期时间period有正有负,这是ScheduledThreadPoolExecutor的ScheduledAtFixedRate和ScheduledWithFixedDelay的方法区别,前者为正数,后者为负数 。2.正数时,下一次执行时间为原来的执行时间+周期 , 即以执行开始时间为基准 。3.负数时 , 不考虑溢出情况 , 下一次执行时间为当前时间+周期 , 即以执行结束时间为基准 。如果溢出 , 下一次执行时间为Long.MAX_VALUE + headDelay 。
疑问说明(这一步有兴趣的需要自己去调试然后在核心方法处断点查看就可以了)
其实只要当做作System.nanoTime() + delay就可以了 , 没必要关注overflowFree这一步,原因:
1.如果执行了 Long.MAX_VALUE + headDelay,triggerTime方法会获得负数,示例代码
executor.scheduleAtFixedRate(task, 20, 1244574199069500L, TimeUnit.NANOSECONDS);//任延迟取最大值 稳定定时器executor.scheduleWithFixedDelay(task, 1, 9223272036854775807L, TimeUnit.NANOSECONDS); //任务+延迟2.如果不执行 Long.MAX_VALUE + headDelay,triggerTime方法也有可能获得负数,示例代码:
executor.scheduleAtFixedRate(task, 20, 4611686018427387900L, TimeUnit.NANOSECONDS);executor.scheduleWithFixedDelay(task, 1, 9223272036854775807L, TimeUnit.NANOSECONDS); 3.而且获得负数在compareTo这一步不影响排序 。【可能是由于科技发展的缘故吧,现在Long.MAX_VALUE【9223372036854775807L】溢出了,就会变为-9223372036854775808L,对排序不影响】
【5】ScheduledThreadPoolExecutor类源码分析
1.ScheduledThreadPoolExecutor的四种使用方法
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();RunnableScheduledFuture<Void> t = decorateTask(command, new ScheduledFutureTask<Void>(command, null, triggerTime(delay, unit), sequencer.getAndIncrement()));delayedExecute(t);return t;}public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay,TimeUnit unit) {if (callable == null || unit == null)throw new NullPointerException();RunnableScheduledFuture<V> t = decorateTask(callable, new ScheduledFutureTask<V>(callable, triggerTime(delay, unit), sequencer.getAndIncrement()));delayedExecute(t);return t;}public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (delay <= 0L)throw new IllegalArgumentException();//这里设置的-unit.toNanos(delay)是负数ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null, triggerTime(initialDelay, unit), -unit.toNanos(delay), sequencer.getAndIncrement());//这个方法是用于以后做扩展的RunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;delayedExecute(t);return t;}public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay, long period,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (period <= 0L)throw new IllegalArgumentException();//这里设置unit.toNanos(period)是正数ScheduledFutureTask<Void> sft = new ScheduledFutureTask<Void>(command, null,triggerTime(initialDelay, unit), unit.toNanos(period), sequencer.getAndIncrement());//这个方法是用于以后做扩展的RunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;delayedExecute(t);return t;}
推荐阅读
- 苹果手机怎么复制截屏(苹果手机咋部分截屏)
- 玉米有部分坏了 玉米坏了是什么样的
- 怀孕期间都需要补充什么营养品 怀孕期间每个月需要补充什么营养
- 苏科版八年级上册物理补充答案 苏科版八年级物理上册教案
- 苏科版九年级上册物理补充答案 苏科版九年级上册物理教案
- 捷豹xel多少钱 捷豹XEL多少钱
- 芫花根的药理作用
- 光遇表演者在哪里? 光遇表演者在哪里
- iPhone xs屏幕多少钱
- 常识判断豆丁网