专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

高并发深度解析ScheduledThreadPoolExec

  在【高并发专题】的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类。今天我们就来一起手撕ScheduledThreadPoolExecutor类的源代码。构造方法
  我们先来看下ScheduledThreadPoolExecutor的构造方法,源代码如下所示。publicScheduledThreadPoolExecutor(intcorePoolSize){super(corePoolSize,Integer。MAXVALUE,0,NANOSECONDS,newDelayedWorkQueue());}publicScheduledThreadPoolExecutor(intcorePoolSize,ThreadFactorythreadFactory){super(corePoolSize,Integer。MAXVALUE,0,NANOSECONDS,newDelayedWorkQueue(),threadFactory);}publicScheduledThreadPoolExecutor(intcorePoolSize,RejectedExecutionHandlerhandler){super(corePoolSize,Integer。MAXVALUE,0,NANOSECONDS,newDelayedWorkQueue(),handler);}publicScheduledThreadPoolExecutor(intcorePoolSize,ThreadFactorythreadFactory,RejectedExecutionHandlerhandler){super(corePoolSize,Integer。MAXVALUE,0,NANOSECONDS,newDelayedWorkQueue(),threadFactory,handler);}
  从代码结构上来看,ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,ScheduledThreadPoolExecutor类的构造方法实际上调用的是ThreadPoolExecutor类的构造方法。schedule方法
  接下来,我们看一下ScheduledThreadPoolExecutor类的schedule方法,源代码如下所示。publicScheduledFuturelt;?schedule(Runnablecommand,longdelay,TimeUnitunit){如果传递的Runnable对象和TimeUnit时间单位为空抛出空指针异常if(commandnullunitnull)thrownewNullPointerException();封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象RunnableScheduledFuturelt;?tdecorateTask(command,newScheduledFutureTaskVoid(command,null,triggerTime(delay,unit)));执行延时任务delayedExecute(t);返回任务returnt;}publicVScheduledFutureVschedule(CallableVcallable,longdelay,TimeUnitunit)如果传递的Callable对象和TimeUnit时间单位为空抛出空指针异常if(callablenullunitnull)thrownewNullPointerException();封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象RunnableScheduledFutureVtdecorateTask(callable,newScheduledFutureTaskV(callable,triggerTime(delay,unit)));执行延时任务delayedExecute(t);返回任务returnt;}
  从源代码可以看出,ScheduledThreadPoolExecutor类提供了两个重载的schedule方法,两个schedule方法的第一个参数不同。可以传递Runnable接口对象,也可以传递Callable接口对象。在方法内部,会将Runnable接口对象和Callable接口对象封装成RunnableScheduledFuture对象,本质上就是封装成ScheduledFutureTask对象。并通过delayedExecute方法来执行延时任务。
  在源代码中,我们看到两个schedule都调用了decorateTask方法,接下来,我们就看看decorateTask方法。decorateTask方法
  decorateTask方法源代码如下所示。protectedVRunnableScheduledFutureVdecorateTask(Runnablerunnable,RunnableScheduledFutureVtask){returntask;}protectedVRunnableScheduledFutureVdecorateTask(CallableVcallable,RunnableScheduledFutureVtask){returntask;}
  通过源码可以看出decorateTask方法的实现比较简单,接收一个Runnable接口对象或者Callable接口对象和封装的RunnableScheduledFuture任务,两个方法都是将RunnableScheduledFuture任务直接返回。在ScheduledThreadPoolExecutor类的子类中可以重写这两个方法。
  接下来,我们继续看下scheduleAtFixedRate方法。scheduleAtFixedRate方法
  scheduleAtFixedRate方法源代码如下所示。publicScheduledFuturelt;?scheduleAtFixedRate(Runnablecommand,longinitialDelay,longperiod,TimeUnitunit){传入的Runnable对象和TimeUnit为空,则抛出空指针异常if(commandnullunitnull)thrownewNullPointerException();如果执行周期period传入的数值小于或者等于0抛出非法参数异常if(period0)thrownewIllegalArgumentException();将Runnable对象封装成ScheduledFutureTask任务,并设置执行周期ScheduledFutureTaskVoidsftnewScheduledFutureTaskVoid(command,null,triggerTime(initialDelay,unit),unit。toNanos(period));调用decorateTask方法,本质上还是直接返回ScheduledFutureTask对象RunnableScheduledFutureVoidtdecorateTask(command,sft);设置执行的任务sft。outerTaskt;执行延时任务delayedExecute(t);返回执行的任务returnt;}
  通过源码可以看出,scheduleAtFixedRate方法将传递的Runnable对象封装成ScheduledFutureTask任务对象,并设置了执行周期,下一次的执行时间相对于上一次的执行时间来说,加上了period时长,时长的具体单位由TimeUnit决定。采用固定的频率来执行定时任务。
  ScheduledThreadPoolExecutor类中另一个定时调度任务的方法是scheduleWithFixedDelay方法,接下来,我们就一起看看scheduleWithFixedDelay方法。scheduleWithFixedDelay方法
  scheduleWithFixedDelay方法的源代码如下所示。publicScheduledFuturelt;?scheduleWithFixedDelay(Runnablecommand,longinitialDelay,longdelay,TimeUnitunit){传入的Runnable对象和TimeUnit为空,则抛出空指针异常if(commandnullunitnull)thrownewNullPointerException();任务延时时长小于或者等于0,则抛出非法参数异常if(delay0)thrownewIllegalArgumentException();将Runnable对象封装成ScheduledFutureTask任务并设置固定的执行周期来执行任务ScheduledFutureTaskVoidsftnewScheduledFutureTaskVoid(command,null,triggerTime(initialDelay,unit),unit。toNanos(delay));调用decorateTask方法,本质上直接返回ScheduledFutureTask任务RunnableScheduledFutureVoidtdecorateTask(command,sft);设置执行的任务sft。outerTaskt;执行延时任务delayedExecute(t);返回任务returnt;}
  从scheduleWithFixedDelay方法的源代码,我们可以看出在将Runnable对象封装成ScheduledFutureTask时,设置了执行周期,但是此时设置的执行周期与scheduleAtFixedRate方法设置的执行周期不同。此时设置的执行周期规则为:下一次任务执行的时间是上一次任务完成的时间加上delay时长,时长单位由TimeUnit决定。也就是说,具体的执行时间不是固定的,但是执行的周期是固定的,整体采用的是相对固定的延迟来执行定时任务。
  如果大家细心的话,会发现在scheduleWithFixedDelay方法中设置执行周期时,传递的delay值为负数,如下所示。ScheduledFutureTaskVoidsftnewScheduledFutureTaskVoid(command,null,triggerTime(initialDelay,unit),unit。toNanos(delay));
  这里的负数表示的是相对固定的延迟。
  在ScheduledFutureTask类中,存在一个setNextRunTime方法,这个方法会在run方法执行完任务后调用,这个方法更能体现scheduleAtFixedRate方法和scheduleWithFixedDelay方法的不同,setNextRunTime方法的源码如下所示。privatevoidsetNextRunTime(){距离下次执行任务的时长longpperiod;固定频率执行,上次执行任务的时间加上任务的执行周期if(p0)timep;相对固定的延迟使用的是系统当前时间加上任务的执行周期elsetimetriggerTime(p);}
  在setNextRunTime方法中通过对下次执行任务的时长进行判断来确定是固定频率执行还是相对固定的延迟。triggerTime方法
  在ScheduledThreadPoolExecutor类中提供了两个triggerTime方法,用于获取下一次执行任务的具体时间。triggerTime方法的源码如下所示。privatelongtriggerTime(longdelay,TimeUnitunit){returntriggerTime(unit。toNanos((delay0)?0:delay));}longtriggerTime(longdelay){returnnow()((delay(Long。MAXVALUE1))?delay:overflowFree(delay));}
  这两个triggerTime方法的代码比较简单,就是获取下一次执行任务的具体时间。有一点需要注意的是:delay(Long。MAXVALUE1判断delay的值是否小于Long。MAXVALUE的一半,如果小于Long。MAXVALUE值的一半,则直接返回delay,否则需要处理溢出的情况。
  我们看到在triggerTime方法中处理防止溢出的逻辑使用了overflowFree方法,接下来,我们就看看overflowFree方法的实现。overflowFree方法
  overflowFree方法的源代码如下所示。privatelongoverflowFree(longdelay){获取队列中的节点Delayedhead(Delayed)super。getQueue()。peek();获取的节点不为空,则进行后续处理if(head!null){从队列节点中获取延迟时间longheadDelayhead。getDelay(NANOSECONDS);如果从队列中获取的延迟时间小于0,并且传递的delay值减去从队列节点中获取延迟时间小于0if(headDelay0(delayheadDelay0))将delay的值设置为Long。MAXVALUEheadDelaydelayLong。MAXVALUEheadDelay;}返回延迟时间returndelay;}
  通过对overflowFree方法的源码分析,可以看出overflowFree方法本质上就是为了限制队列中的所有节点的延迟时间在Long。MAXVALUE值之内,防止在ScheduledFutureTask类中的compareTo方法中溢出。
  ScheduledFutureTask类中的compareTo方法的源码如下所示。publicintcompareTo(Delayedother){if(otherthis)comparezeroifsameobjectreturn0;if(otherinstanceofScheduledFutureTask){ScheduledFutureTasklt;?x(ScheduledFutureTasklt;?)other;longdifftimex。time;if(diff0)return1;elseif(diff0)return1;elseif(sequenceNumberx。sequenceNumber)return1;elsereturn1;}longdiffgetDelay(NANOSECONDS)other。getDelay(NANOSECONDS);return(diff0)?1:(diff0)?1:0;}
  compareTo方法的主要作用就是对各延迟任务进行排序,距离下次执行时间靠前的任务就排在前面。delayedExecute方法
  delayedExecute方法是ScheduledThreadPoolExecutor类中延迟执行任务的方法,源代码如下所示。privatevoiddelayedExecute(RunnableScheduledFuturelt;?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方法的源码实现如下所示。booleancanRunInCurrentRunState(booleanperiodic){returnisRunningOrShutdown(periodic?continueExistingPeriodicTasksAfterShutdown:executeExistingDelayedTasksAfterShutdown);}
  可以看到canRunInCurrentRunState方法的逻辑比较简单,就是判断线程池当前状态下能够执行任务。
  另外,在delayedExecute方法内部还调用了ThreadPoolExecutor类中的ensurePrestart()方法,接下来,我们看下ThreadPoolExecutor类中的ensurePrestart()方法的实现,如下所示。voidensurePrestart(){intwcworkerCountOf(ctl。get());if(wccorePoolSize)addWorker(null,true);elseif(wc0)addWorker(null,false);}
  在ThreadPoolExecutor类中的ensurePrestart()方法中,首先获取当前线程池中线程的数量,如果线程数量小于corePoolSize则调用addWorker方法传递null和true,如果线程数量为0,则调用addWorker方法传递null和false。
  关于addWork()方法的源码解析,大家可以参考【高并发专题】中的《高并发之通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程》一文,这里,不再赘述。reExecutePeriodic方法
  reExecutePeriodic方法的源代码如下所示。voidreExecutePeriodic(RunnableScheduledFuturelt;?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方法是一个空方法,如下所示。voidonShutdown(){}
  ThreadPoolExecutor类中的onShutdown方法交由子类实现,所以ScheduledThreadPoolExecutor类覆写了onShutdown方法,实现了具体的逻辑,ScheduledThreadPoolExecutor类中的onShutdown方法的源码实现如下所示。OverridevoidonShutdown(){获取队列BlockingQueueRunnableqsuper。getQueue();在线程池已经调用shutdown方法后,是否继续执行现有延迟任务booleankeepDelayedgetExecuteExistingDelayedTasksAfterShutdownPolicy();在线程池已经调用shutdown方法后,是否继续执行现有定时任务booleankeepPeriodicgetContinueExistingPeriodicTasksAfterShutdownPolicy();在线程池已经调用shutdown方法后,不继续执行现有延迟任务和定时任务if(!keepDelayed!keepPeriodic){遍历队列中的所有任务for(Objecte:q。toArray())取消任务的执行if(einstanceofRunnableScheduledFuturelt;?)((RunnableScheduledFuturelt;?)e)。cancel(false);清空队列q。clear();}在线程池已经调用shutdown方法后,继续执行现有延迟任务和定时任务else{遍历队列中的所有任务for(Objecte:q。toArray()){当前任务是RunnableScheduledFuture类型if(einstanceofRunnableScheduledFuture){将任务强转为RunnableScheduledFuture类型RunnableScheduledFuturelt;?t(RunnableScheduledFuturelt;?)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类中的核心方法的源代码,我们就分析完了。

云顶之弈12。10更新详解,发明家与德莱文大砍,黑魔枪归来兄弟们好,我是摩昂解说,版本的强势阵容均在弈图排行榜!摩昂还针对云顶与金铲铲不同的对局环境,对阵容强度分别进行了标注,会贴合版本环境随时更新。周四就会上线12。10版本,这是S6。辞职后,我在北京替人跑腿,月入数万元天下网商朱之丛编辑李丹超北及海淀昌平,南到丰台大兴,如果把一整天的行程连接起来,马建的轨迹会编织成一张网,纵贯大半个北京城。这样连日奔波的生活,他已过了9年。从2013年起,江苏小2019年50岁大妈执意生3胎,扬言北京4套房养得起,怀不上就做试管有一些来自失独家庭的母亲,会选择在五六十岁的时候重新怀孕。为了找回生存的勇气,她们只能想办法再要一个孩子。能自然受孕的当然最好,如果实在不行的就去尝试试管技术。可是在2019年有这拒绝欧盟对俄石油禁令!匈牙利宣布进入战时紧急状态,局势再升级据外媒报道,匈牙利总理欧尔班近日在社交平台上宣布了一个让人猝不及防的消息,匈牙利将从本月25日开始进入战时紧急状态。结合日前匈牙利才刚拒绝欧盟针对俄罗斯的第六轮制裁,匈牙利此番戒严今天全世界都在看的新闻2022。5。25岸田莫迪单独会谈,拟早日启动日印外交防务22会谈机制日印两国领导人5月24日结束美日澳印四方峰会,傍晚在东京迎宾馆再次单独会谈,会谈持续了1个小时。双方就努力共建自由开放的印太地区卢甘斯克几乎被全部占领,泽连斯基未来几周的战斗将是艰难的五月24日,星期二,乌克兰战争进入了第4个月。目前整个乌战的焦点,是北顿涅茨克城市群,也就是北顿涅茨克和利昌西斯克的包围战俄军目前正在分割包围他们。北顿涅茨克和利昌西斯克是目前卢甘罗马1北京时间5月26日凌晨3时,2122赛季欧会杯决赛在费耶诺德与罗马之间展开,我们将会目睹首支该项赛事的冠军产生!赛前费耶诺德主帅斯洛特接受了欧足联官方的采访,他表示穆里尼奥赢得过很没有相控阵雷达,没有远程防空导弹,中国继续建造054A还有啥用?2008年海军第一艘054A型护卫舰529舟山舰入列东海舰队,舟山舰的服役拉开了我国继053系列后又一次护卫舰建造高潮!2019年542号枣庄舰的服役代表着海军首轮054A建造工作近20年,美校园大型枪击惨案近二十五年,发生在美国校园的大型枪击惨案1999年4月20日科罗拉多州哥伦拜恩高中,一名少年手持武器和自制炸弹冲入校园,造成12名学生1名教师死亡,24人受伤2007年4月弗吉尼亚董思怡增肥15斤演二十不惑,瘦下来秒变甜妹,还成古偶女主二十不惑带火了饰演段家宝的女演员董思怡!在这部剧开播前,她在业内就是个小透明,但在二十不惑里段家宝的人设太好了,人美心善还有钱,就是有点胖胖的,但肉乎乎的她依旧让人觉得是个美人,五终末的女武神始皇帝获胜!仙境传说第七场终于落下了帷幕由于月更的性质,终末的女武神漫画打一场就需要花费小半年的时间,始皇帝与哈迪斯的对战更是在不断地反转以及回忆当中,虽然现实世界过了许久,但要是做成漫画的话,估计也就是两三集的事情,根
血压高的人,提醒除了盐以外,这3种素食平时也应少吃生活节奏的加快,因为忙碌的工作和生活反而忽视了自己的身体健康,不注重保养,再加上不良的生活和饮食习惯,多种身体不适开始出现在自己的身上。若长时间未引起重视,任由其发展,便容易导致身高胆固醇食物榜单公布鸡蛋排最后,榜首不少人还当补品胆固醇,主要是由肝脏合成少量从食物当中获取,经过人体代谢后一部分转化为甾体激素,而另一部分则称为细胞膜的重要组成,维持血液中胆固醇的正常水平。由此可见,胆固醇在人体组织细胞合成过程年纪大了容易便秘,记住这几招,很轻松便秘,是一种很常见的临床症状。多表现为排便困难,或者排便次数减少,粪便干硬等等,主要原因就是长期的不良生活习惯,导致身体内部多器官运转失调所致,病位主要在大肠,涉及脾胃肺肝肾等多个二陈丸巧搭配,还能治4种病,建议收藏二陈丸作为化痰的中成药来说是比较全面的,它化湿痰,和脾胃。但是如果说你除了痰多还出现了其他的症状,这时候单独用二陈丸就不是很全面了。今天崔医生就教你用二陈丸搭配,来治疗另外4种症状科瓦契奇我现在感觉很不错,回到球场上的感觉真的很好近日,切尔西中场科瓦契奇在接受俱乐部内部媒体的采访时谈到了自己的伤情。对此,这位克罗地亚中场表示自己现在的感觉非常不错,在场边看球的日子非常难熬,但自己在经历了一些康复的训练之后,郝伟白费苦心,泰山队后卫业余表现,郭田雨拖慢节奏存在4大问题郝伟白费苦心,泰山队后卫业余表现,郭田雨拖慢节奏,存在4大问题作为争冠球队,山东泰山队处于落后的位置,不仅仅是积分层面上,争冠当中对于比赛的控制力,踢中下游球队的表现,都没有干净利意外!广东男篮核心后卫再次食言?杜峰朱芳雨看走眼广东男篮在今年夏天的人员变动非常大,两位球队的绝对功勋球员纷纷离开了球队,这两人分别是威姆斯和周鹏,随着这两名球员的离开,球队在外线攻防两端都会遭受到巨大的打击,不过好在球队在锋线李霄鹏下课?曝国足换帅成定局,前中超冠军主帅成候选卡塔尔世界杯将近,过两个月又将会是球迷4年一度狂欢的节目。但是,这样的欢庆与我们中国足球并没有什么关系,因为我们的中国男足已经在积极备战下一届世界杯。在12强赛的失败,临时救火的主射雕英雄传人物战力巅峰不是王重阳,有两高手未显山露水01hr射雕英雄传中,有很明确的武功等级划分。武功巅峰者为华山五绝,而五绝中实力最强的是王重阳。这一结论得自第一次华山论剑。那次比武,五位绝顶高手在华山之巅,足足较量了七天七夜,胜英雄联盟手游体验服更新,全新S7赛季,上线四个新英雄英雄联盟手游体验服于9月5日1000进行不停服更新。更新内容新英雄灵罗娃娃格温在版本更新后上线封魔剑魂永恩将在9月12日上线愁云使者薇古丝将在10月13日上线祖安怒兽沃里克将在10中国男乒7将出战,世青赛冠军刘夜泊30强势开局北京时间9月15日消息,2022年WTT常规挑战赛阿拉木图站展开资格赛的争夺。男单资格赛第一轮,共有7名中国选手出战,打出4个30的比分。其中,世青赛冠军刘夜泊30战胜东道主选手阿
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网