游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

高并发深度解析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类中的核心方法的源代码,我们就分析完了。

太可怕了!森林狼球星爱德华兹受伤惨叫,脚踝变形令人毛骨悚然!在对阵公牛的比赛中,森林狼球星爱德华兹在第一节因扭伤脚踝提前退出比赛。当时,爱德华兹跳投后落地时,脚踝严重变形,这位年仅21岁的全明星发出了可怕的尖叫声,他的惨叫在整个竞技场中……在云端乐享蒸汽浴重庆解放碑威斯汀酒店活力套房体验看到这个标题,或许浮现在你脑海里的,是在一间高空酒店的泳池更衣室里与好友们一起体验汗蒸的画面。这样的场景可能经常在你住过的酒店里面出现,例如在上海浦东丽思卡尔顿酒店、南京丽思卡……徕卡镜头小米12SUltra登场,小米11加速降价,沦为牺牲小米12SUltra还创新加入了徕卡最经典的三大传奇镜头,其中35mm经典黑白镜头模拟经典35mmF1。4镜头,具有独特的黑白质感和人文情怀;50mm经典旋转镜头模拟50F0。……航拍河南荥阳网红矿坑巨大翠绿水坑被山包围垂钓者露营人多航拍河南荥阳网红矿坑,这里在社交平台上曝光率很高。很多网友慕名而来这里游玩,夏天时这块水池是游泳爱好者的乐园。航拍画面可以看到,挖矿形成的巨大翠绿水坑被山包围,水坑……今年你春晚了吗?自从第一届春晚开播以来,每年除夕夜的春晚就成了一家人除夕守岁的文化大餐。还记得小时候那时的电视机还大多是黑白的,彩色电视机对于很多家庭都是一件奢侈品,时间一晃二十来年过去了,现……去年中国失业率5。5,人均GDP1。27万美元,在国际上是什大家都知道,去年是疫情三年中最不容易的一年,在这一年,中国失业率为5。5,人均GDP达到1。27万美元。在人均GDP方面,处于国际什么样的水平呢?今天,国家统计局相关领导……做投资,是要顺势而为,还是要逆势而动?做投资,是要顺势而为,还是要逆势而动?文金立成(注:本文1800字左右,阅读大概需要3分钟,这是立成说投资第472篇原创文章)经过最近一年来市场的疯狂、超预期……2016年,高考状元辍学创业,两年挣了几千万,警方调查后将其炒股赚不了几个钱,其实真正赚钱的是期货,以前跟着我干期货的,数钱数到手抽筋,几个月,十万变百万不是梦!直播间里,推荐股票的讲师大声宣扬。周大爷心中一动,什么期货能这……棋圣聂卫平,1985年让日本三位超一流棋手剃光头平息民愤1985年11月20日,中日第一届围棋擂台赛落幕,中国队以8:7获得冠军。这一届擂台赛跌宕起伏,精彩异常,引起了极大的关注,尤其是中国,竟然掀起一轮爱国热潮,反观日本,第一届擂……女排最美队长魏秋月,夺冠后退役,嫁相恋12年教练,34岁再升中国女排一直是国内三大球里的荣誉之师,历史上拿到过不少冠军奖杯,多次在国际大赛里实现升国旗、唱国歌,让中国女排的威名享誉国际!其中的功勋离不开一代代女排队员们的努力,不少球员为……日产汽车中国区发布销量业绩9月共售92071辆中国网汽车10月12日讯(记者王芳)日前,日产公布了其今年9月份和19月份的中国区销量。据统计,9月份,日产销量达92071辆,涵盖乘用车及轻型商用车,同比下降11。8。东风汽……盘点今年的万圣节服装,各国明星以标志性的万圣节服装引领潮流谈到今年的万圣节服装,英国和爱尔兰的名人都让粉丝们惊叹不已,一些国家最喜欢的明星在以怪异的新面貌前往派对时看起来面目全非在今年庆祝万圣节时,英国和爱尔兰的明星们已经全力以……
1009,下半场血洗对手男篮亚洲杯小组赛,日本男篮对阵哈萨克斯坦男篮,最终,日本队10068狂胜对手,真是太强了,第四节单节轰出了269的攻势,而且在下半场,日本队合计打出了5520的攻势,真是血洗对……刘强东的一句狠话京东砸出百亿补贴2023,低过拼多多?2022年年底,曾经被认为已经不再管理京东的刘强东,再度出现了大众视野当中,并且还放出一句狠话低价是京东过去成功最重要的武器,以后也是唯一基础性武器。这句狠话不禁让人想到……华为Mate50E或将于10月8日开启预售售价3999元起【手机中国新闻】从华为Mate50系列开售至今,一直是处于一机难求的状态,昆仑玻璃版本市场加价千元,保时捷版本加价更是高达近万元,受欢迎程度可见一斑。目前有消息称,目前华为正在……退休奶奶经常带孙女做一件事,孩子的智力得到了开发,专注力超强妈妈,我的贴纸书又贴完啦,你再给我买几本吧。这是女儿经常给我说的一句话。自从女儿2岁多时由婆婆照顾,就喜欢上了贴纸书游戏,贴了100多本了,总也玩不够。婆婆退休前是语文教……酷比魔方i7Book笔记本发布昔日旗舰i76660U,299IT之家8月8日消息酷比魔方i7Book今天下午正式发布,搭载了英特尔6代低压酷睿的旗舰处理器i76660U,8GB内存256GBSSD,预售价2999元,首发100元定金可抵……酷比魔方旗舰笔记本i7Book配置公布6代i7,锐炬540核IT之家8月8日消息酷比魔方将在今天下午发布i7Book笔记本,官方已经公布了大致的配置参数:搭载英特尔i7高性能处理器,锐距Graphics540性能级显卡51。……公牛推出小白PD快充插排支持65W笔记本快充IT之家8月7日消息公牛现已上架了小白PD快充USB插座,搭载了3个USB快充插孔和6个充电孔位,售价为199元。IT之家了解到,作为一款PD充电器,这款插排的USBC接……联想高配版R7000P国内即将推出可选R74800HRTX2IT之家7月22日消息7月17日,联想海外发布了高配版的Legion5和Legion5P笔记本,也就是国内的拯救者R7000和R7000P,最高配备了R74800HRTX206……书女儿同学的妈妈故事要从我准备睡觉时,手机突然响了一声说起。这晚,和往常一样,睡觉前我拿着手机刷抖音,手机突然响了一声。我点开一看,是微信出现了一条好友申请的提示。是女儿幼儿……通州永乐店将成京津冀地区微中心,又一楼市刚需板块出现?从2021年至今,房地产行业风云变幻,市场波动成为了目前行业主旋律。房地产营销人员是市场一线人员,也是最快能感受到市场变化的人,在北京K2十里春风营销负责人看来,以前的房……三大运营商(移动电信联通)的组织架构解析移动、电信、联通作为三家国有运营商企业,是大家平时经常会接触到但又不是十分了解的。同时每年的春秋两季也会有大批量的校园招聘吸纳毕业生就业,本篇文章全面概括了这三家国企的发展和架……曝英特尔11代移动标压处理器明年Q1发布,支持DDR5内存IT之家8月3日消息根据外媒VideoCardz的消息,9月2日,英特尔将推出其TigerLakeU系列处理器,采用WillowCove架构和Xe核显。爆料者momomous的……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网