范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

高并发深度解析ScheduledThreadPoolExecutor类的源代码

  在【高并发专题】的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类。今天我们就来一起手撕ScheduledThreadPoolExecutor类的源代码。  构造方法
  我们先来看下ScheduledThreadPoolExecutor的构造方法,源代码如下所示。  public ScheduledThreadPoolExecutor(int corePoolSize) {  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }  public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,     new DelayedWorkQueue(), threadFactory); }  public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,     new DelayedWorkQueue(), handler); }  public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,     new DelayedWorkQueue(), threadFactory, handler); }
  从代码结构上来看,ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,ScheduledThreadPoolExecutor类的构造方法实际上调用的是ThreadPoolExecutor类的构造方法。  schedule方法
  接下来,我们看一下ScheduledThreadPoolExecutor类的schedule方法,源代码如下所示。  public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {  //如果传递的Runnable对象和TimeUnit时间单位为空  //抛出空指针异常  if (command == null || unit == null)   throw new NullPointerException();  //封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象  RunnableScheduledFuture<?> t = decorateTask(command, new ScheduledFutureTask(command, null, triggerTime(delay, unit)));  //执行延时任务  delayedExecute(t);  //返回任务  return t; }  public  ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit)   //如果传递的Callable对象和TimeUnit时间单位为空  //抛出空指针异常  if (callable == null || unit == null)   throw new NullPointerException();  //封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象  RunnableScheduledFuture t = decorateTask(callable,   new ScheduledFutureTask(callable, triggerTime(delay, unit)));  //执行延时任务  delayedExecute(t);  //返回任务  return t; }
  从源代码可以看出,ScheduledThreadPoolExecutor类提供了两个重载的schedule方法,两个schedule方法的第一个参数不同。可以传递Runnable接口对象,也可以传递Callable接口对象。在方法内部,会将Runnable接口对象和Callable接口对象封装成RunnableScheduledFuture对象,本质上就是封装成ScheduledFutureTask对象。并通过delayedExecute方法来执行延时任务。
  在源代码中,我们看到两个schedule都调用了decorateTask方法,接下来,我们就看看decorateTask方法。  decorateTask方法
  decorateTask方法源代码如下所示。  protected  RunnableScheduledFuture decorateTask(Runnable runnable, RunnableScheduledFuture task) {  return task; }  protected  RunnableScheduledFuture decorateTask(Callable callable, RunnableScheduledFuture task) {  return task; }
  通过源码可以看出decorateTask方法的实现比较简单,接收一个Runnable接口对象或者Callable接口对象和封装的RunnableScheduledFuture任务,两个方法都是将RunnableScheduledFuture任务直接返回。在ScheduledThreadPoolExecutor类的子类中可以重写这两个方法。
  接下来,我们继续看下scheduleAtFixedRate方法。  scheduleAtFixedRate方法
  scheduleAtFixedRate方法源代码如下所示。  public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {  //传入的Runnable对象和TimeUnit为空,则抛出空指针异常  if (command == null || unit == null)   throw new NullPointerException();  //如果执行周期period传入的数值小于或者等于0  //抛出非法参数异常  if (period <= 0)   throw new IllegalArgumentException();  //将Runnable对象封装成ScheduledFutureTask任务,  //并设置执行周期  ScheduledFutureTask sft =   new ScheduledFutureTask(command, null, triggerTime(initialDelay, unit), unit.toNanos(period));  //调用decorateTask方法,本质上还是直接返回ScheduledFutureTask对象  RunnableScheduledFuture t = decorateTask(command, sft);  //设置执行的任务  sft.outerTask = t;  //执行延时任务  delayedExecute(t);  //返回执行的任务  return t; }
  通过源码可以看出,scheduleAtFixedRate方法将传递的Runnable对象封装成ScheduledFutureTask任务对象,并设置了执行周期,下一次的执行时间相对于上一次的执行时间来说,加上了period时长,时长的具体单位由TimeUnit决定。采用固定的频率来执行定时任务。
  ScheduledThreadPoolExecutor类中另一个定时调度任务的方法是scheduleWithFixedDelay方法,接下来,我们就一起看看scheduleWithFixedDelay方法。  scheduleWithFixedDelay方法
  scheduleWithFixedDelay方法的源代码如下所示。  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {  //传入的Runnable对象和TimeUnit为空,则抛出空指针异常  if (command == null || unit == null)   throw new NullPointerException();  //任务延时时长小于或者等于0,则抛出非法参数异常  if (delay <= 0)   throw new IllegalArgumentException();  //将Runnable对象封装成ScheduledFutureTask任务  //并设置固定的执行周期来执行任务  ScheduledFutureTask sft =   new ScheduledFutureTask(command, null,triggerTime(initialDelay, unit), unit.toNanos(-delay));  //调用decorateTask方法,本质上直接返回ScheduledFutureTask任务  RunnableScheduledFuture t = decorateTask(command, sft);  //设置执行的任务  sft.outerTask = t;  //执行延时任务  delayedExecute(t);  //返回任务  return t; }
  从scheduleWithFixedDelay方法的源代码,我们可以看出在将Runnable对象封装成ScheduledFutureTask时,设置了执行周期,但是此时设置的执行周期与scheduleAtFixedRate方法设置的执行周期不同。此时设置的执行周期规则为:下一次任务执行的时间是上一次任务完成的时间加上delay时长,时长单位由TimeUnit决定。也就是说,具体的执行时间不是固定的,但是执行的周期是固定的,整体采用的是相对固定的延迟来执行定时任务。
  如果大家细心的话,会发现在scheduleWithFixedDelay方法中设置执行周期时,传递的delay值为负数,如下所示。  ScheduledFutureTask sft =   new ScheduledFutureTask(command, null, triggerTime(initialDelay, unit), unit.toNanos(-delay));
  这里的负数表示的是相对固定的延迟。
  在ScheduledFutureTask类中,存在一个setNextRunTime方法,这个方法会在run方法执行完任务后调用,这个方法更能体现scheduleAtFixedRate方法和scheduleWithFixedDelay方法的不同,setNextRunTime方法的源码如下所示。  private void setNextRunTime() {  //距离下次执行任务的时长  long p = period;  //固定频率执行,  //上次执行任务的时间  //加上任务的执行周期  if (p > 0)   time += p;  //相对固定的延迟  //使用的是系统当前时间  //加上任务的执行周期  else   time = triggerTime(-p); }
  在setNextRunTime方法中通过对下次执行任务的时长进行判断来确定是固定频率执行还是相对固定的延迟。  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方法中处理防止溢出的逻辑使用了overflowFree方法,接下来,我们就看看overflowFree方法的实现。  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值之内,防止在ScheduledFutureTask类中的compareTo方法中溢出。
  ScheduledFutureTask类中的compareTo方法的源码如下所示。  public int compareTo(Delayed other) {  if (other == this) // compare zero if same object   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; }
  compareTo方法的主要作用就是对各延迟任务进行排序,距离下次执行时间靠前的任务就排在前面。  delayedExecute方法
  delayedExecute方法是ScheduledThreadPoolExecutor类中延迟执行任务的方法,源代码如下所示。  private void delayedExecute(RunnableScheduledFuture<?> task) {  //如果当前线程池已经关闭  //则执行线程池的拒绝策略  if (isShutdown())   reject(task);  //线程池没有关闭  else {   //将任务添加到阻塞队列中   super.getQueue().add(task);   //如果当前线程池是SHUTDOWN状态   //并且当前线程池状态下不能执行任务   //并且成功从阻塞队列中移除任务   if (isShutdown() &&    !canRunInCurrentRunState(task.isPeriodic()) &&    remove(task))    //取消任务的执行,但不会中断执行中的任务    task.cancel(false);   else    //调用ThreadPoolExecutor类中的ensurePrestart()方法    ensurePrestart();  } }
  可以看到在delayedExecute方法内部调用了canRunInCurrentRunState方法,canRunInCurrentRunState方法的源码实现如下所示。  boolean canRunInCurrentRunState(boolean periodic) {  return isRunningOrShutdown(periodic ? continueExistingPeriodicTasksAfterShutdown : executeExistingDelayedTasksAfterShutdown); }
  可以看到canRunInCurrentRunState方法的逻辑比较简单,就是判断线程池当前状态下能够执行任务。
  另外,在delayedExecute方法内部还调用了ThreadPoolExecutor类中的ensurePrestart()方法,接下来,我们看下ThreadPoolExecutor类中的ensurePrestart()方法的实现,如下所示。  void ensurePrestart() {  int wc = workerCountOf(ctl.get());  if (wc < corePoolSize)   addWorker(null, true);  else if (wc == 0)   addWorker(null, false); }
  在ThreadPoolExecutor类中的ensurePrestart()方法中,首先获取当前线程池中线程的数量,如果线程数量小于corePoolSize则调用addWorker方法传递null和true,如果线程数量为0,则调用addWorker方法传递null和false。
  关于addWork()方法的源码解析,大家可以参考【高并发专题】中的《高并发之——通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程》一文,这里,不再赘述。  reExecutePeriodic方法
  reExecutePeriodic方法的源代码如下所示。  void reExecutePeriodic(RunnableScheduledFuture<?> task) {  //线程池当前状态下能够执行任务  if (canRunInCurrentRunState(true)) {   //将任务放入队列   super.getQueue().add(task);   //线程池当前状态下不能执行任务,并且成功移除任务   if (!canRunInCurrentRunState(true) && remove(task))    //取消任务    task.cancel(false);   else    //调用ThreadPoolExecutor类的ensurePrestart()方法    ensurePrestart();  } }
  总体来说reExecutePeriodic方法的逻辑比较简单,但是,这里需要注意和delayedExecute方法的不同点:调用reExecutePeriodic方法的时候已经执行过一次任务,所以,并不会触发线程池的拒绝策略;传入reExecutePeriodic方法的任务一定是周期性的任务。  onShutdown方法
  onShutdown方法是ThreadPoolExecutor类中的钩子函数,它是在ThreadPoolExecutor类中的shutdown方法中调用的,而在ThreadPoolExecutor类中的onShutdown方法是一个空方法,如下所示。  void onShutdown() { }
  ThreadPoolExecutor类中的onShutdown方法交由子类实现,所以ScheduledThreadPoolExecutor类覆写了onShutdown方法,实现了具体的逻辑,ScheduledThreadPoolExecutor类中的onShutdown方法的源码实现如下所示。  @Override void onShutdown() {  //获取队列  BlockingQueue q = super.getQueue();  //在线程池已经调用shutdown方法后,是否继续执行现有延迟任务  boolean keepDelayed = getExecuteExistingDelayedTasksAfterShutdownPolicy();  //在线程池已经调用shutdown方法后,是否继续执行现有定时任务  boolean keepPeriodic = getContinueExistingPeriodicTasksAfterShutdownPolicy();  //在线程池已经调用shutdown方法后,不继续执行现有延迟任务和定时任务  if (!keepDelayed && !keepPeriodic) {   //遍历队列中的所有任务   for (Object e : q.toArray())    //取消任务的执行    if (e instanceof RunnableScheduledFuture<?>)     ((RunnableScheduledFuture<?>) e).cancel(false);   //清空队列   q.clear();  }  //在线程池已经调用shutdown方法后,继续执行现有延迟任务和定时任务  else {   //遍历队列中的所有任务   for (Object e : q.toArray()) {    //当前任务是RunnableScheduledFuture类型    if (e instanceof RunnableScheduledFuture) {     //将任务强转为RunnableScheduledFuture类型     RunnableScheduledFuture<?> t = (RunnableScheduledFuture<?>)e;     //在线程池调用shutdown方法后不继续的延迟任务或周期任务     //则从队列中删除并取消任务     if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||      t.isCancelled()) {      if (q.remove(t))       t.cancel(false);     }    }   }  }  //最终调用tryTerminate()方法  tryTerminate(); }
  ScheduledThreadPoolExecutor类中的onShutdown方法的主要逻辑就是先判断线程池调用shutdown方法后,是否继续执行现有的延迟任务和定时任务,如果不再执行,则取消任务并清空队列;如果继续执行,将队列中的任务强转为RunnableScheduledFuture对象之后,从队列中删除并取消任务。大家需要好好理解这两种处理方式。最后调用ThreadPoolExecutor类的tryTerminate方法。有关ThreadPoolExecutor类的tryTerminate方法的源码解析,大家可以参考【高并发专题】中的《高并发之——通过源码深度分析线程池中Worker线程的执行流程》一文,这里不再赘述。
  至此,ScheduledThreadPoolExecutor类中的核心方法的源代码,我们就分析完了。

获多个国际首次发现中国天眼有望确定快速射电暴中心引擎机制快速射电暴和宿主星系艺术想象图。中国天眼(左)和美国凯克望远镜(右)承担本次研究观测。喻京川傅海绘图中新网北京9月21日电(记者孙自法)作为宇宙中偶发的射电爆发事件,快速射电暴(f安徽第二大城市,为何会有5个市辖区,比合肥还多一个安徽第一大城市是合肥,第二大城市是芜湖,这个是没有争议的。安徽的建省历史不长,不过省会的变动却相当频繁,直到1952年明确为合肥之后,至今再也没有发生过更改。合肥靠着省会的优势,这印度91岁僧人78年不吃不喝?军方在其房间装上监控,最终发现真相2010年春,一位名为杰尼的九十一岁老人登上了印度的各类知名媒体,瞬间火遍大街小巷。据报道,这位老人是一名苦行僧,自打他十三岁下定决心成为苦行僧之时,他就再也没吃过一口饭,喝过一口黑科技!四川德阳推出这款可在手机上操作的政策机器人企业政策获取渠道少?知晓度不高项目申报跑腿多?反映诉求不通畅?在过去很长一段时间里企业追着政策跑一直困扰着德阳大部分企业。为深入推进放管服改革,持续优化营商环境,打通政策落地见效最所罗门群岛一带一路建设者暴徒曾冲进项目烧毁仓库北京日报客户端记者白波接受北京日报客户端记者采访时,黄鹏飞正在所罗门群岛西部省的蒙达国际机场项目上。蒙达国际机场是所罗门群岛两座国际机场之一。机场航站楼年久失修,由黄鹏飞所在的中国加盟充电桩项目,月入5w?谨慎了加盟充电桩项目,月入5w?谨慎了!新能源是近年来最火的赛道,很多小伙伴都希望能分一杯羹。2021年中国新能源乘用车销量达332万辆。然而,新能源汽车保有量激增,但是充电桩确实一桩难缓解女性生育焦虑,除了辅助生殖,这两项政策民众呼声最高辅助生殖能缓解女性的生育焦虑吗最近这个问题被冲上头条热榜。对大多数女性来说,肯定不能啊!女性生育焦虑的原因很复杂,生理心理和社会因素都有。那些能够自然生育,不需要辅助生殖的女性,同取保候审理应是常态张夏文近日,最高法最高检公安部国安部联合印发关于取保候审若干问题的规定,对刑事诉讼活动中的取保候审强制措施的适用和执行做了新的具体规定。该规定是对执行了20多年的原规定的重大修订,泰国女警囚禁30岁女兵做奴隶?!残忍虐待震惊全泰电棍插嘴等最近有一桩震撼了整个泰国,一名43岁的女警竟然将30岁女子控制在家中做奴隶!泰网友曝出的女警照片在长达两年的时间里,女警对受害者进行了彻底的身心虐待。电棍插嘴用棍棒金属尺等暴力殴打他获释了,ampampquot换了200个战俘ampampquot文观察者网王沫初当地时间21日,在沙特和土耳其的斡旋下,俄乌双方在乌克兰北部切尔尼戈夫州进行了战俘交换,涉及近300人。这也是冲突以来的最大规模战俘交换。根据协议,俄方释放了215驾驶感受提升,首搭第四代iMMD混动系统,试驾广汽本田型格eHEV广汽本田型格自从上市以来,其销量便一路节节攀升。在刚过去的8月份,型格就取得了7292辆新车的销量成绩表现,由此可见,世人对于型格车系的喜爱与认可。就在前不久,我们前往厦门去试驾了
谁陪我们一起虚度那些美好的时光!谁陪我们一起虚度那些美好的时光!在虚度的时光里,我愿意有半床明月半床书作伴。年少时,老师说一寸光阴一寸金。于是上课时,我们都很听话,不敢再交头接耳做小动作,一心想着要用功惜时。老师2023让我们一起去走好运2023让我们一起去走好运原创木渔石老石说话202301031544发表于甘肃今天还是过年期间,先送祝福!过去的一年,我们勇敢地把这个世界据为已有,要么赢得了胜利,要么学到了东西!我已走到人生边上看到男性平均年龄七五岁,即想到活三千个日子,三十多万养老金等数字,顿感自己已走到人生边上。六十七岁的我那天灵魂升天,只有上天知道,当然身体素质也知道,因为它才知与病毒的和谐度,适应私藏很久的深情又温柔的小众文案1。按照大自然的规律你该遇到我了。2。保持心脏震荡,有人等你共鸣。3。给时间时间让过去过去让开始开始。4。小众的爱好不用在意大众的眼光。5。所有美好本质除去只剩下你的名字。6。宁静请珍惜每一份相遇,和每一个不离不弃的人!由性入爱难,由爱入性易!人生就是一场赌博没有谁能预测哪一个人会陪自己到最后!所以我很珍惜每一份相遇!每当我看到微信上那几个问都问喘的歪脖子树!大叔总有种被人欺辱的感觉!天下那么大,谈我中考前的自己我从来不羡慕任何人。不管是繁华的大都市,还是平凡的小乡村不论是有钱的高大上,还是贫苦的农民百姓对于我来说,都不过是两个字生活仅此而已!但是,新的日子新的一天我们也要朝着目标奋进!不这一年,谢谢自己!时光飞逝,转眼2022年已经过去。回顾这一年,我们在得失悲喜间泪渡,在起落浮沉中历练,圆满也好,遗憾也罢,辛苦了一整年,我们仍要感谢自己。谢谢在这个即将成为过去的一年里,那个翻滚在如果有人不喜欢你,记住这4句话你就赢了知乎上有一条热评好的关系,不是我们主动去选择的,也不会总是按照我们期待的方式发展。人与人相处,总是充满着未知,有时候,我们想取悦所有人,却令所有人不满。人生在世,无论你如何尽心尽力惊艳!来吴家堡看一年12月,四季变幻的色彩!每个月的吴家堡都有着自己不同的色彩与风景。一年12个月,12抹色彩在吴家堡等待你的脚步。越过高山,跨过低谷,去遇见那个五彩斑斓的吴家堡吧!一月一月,一场雪,济南方特的美色堪比北方雪中国大陆唯一一家,在半导体领域超过美国,全球领先的厂商众所周知,中国大陆在半导体领域,鲜有技术很先进的企业。有几家很牛的企业也就是达到了全球同等水平,比如华为海思在芯片设计水平上,中微半导体在刻蚀机上,与全球顶尖企业处于同一水平。但要扎克伯格对中国的这副吃相,美国媒体都觉得尴尬一边为打击自己的竞争对手在美国鼓动恐华舆论,一边又要依靠中国的工厂来实现自己公司的发展需要近日,美国华盛顿邮报在一篇长文中,讲述了美国知名社交网站脸书的创始人美国Meta公司CEO