线程池的线程是如何复用的
前言
进程和线程的关系相信大家都知道,这里我就不做过多的解释了,既然一个进程是由多个线程组成的,那么线程池又是由若干个线程队列组成的,在并发量比较高的情景下,我们通常会去创建线程池就执行任务,而不单一的创建多个线程去执行任务,因为线程的创建的一系列动作,是需要资源开销的,如果频繁的对线程创建销毁,其实本身是一种很浪费资源的,就更谈不上提高效率了。
一般都会创建线程池将线程统一管理,并且还会引入阻塞和非阻塞队列,接收需要排队处理的任务,但是线程池里的线程是在处理完任务就会进行销毁么,其实并不是这样的,下面我们一起来对线程池里线程是如何复用的进行分析。使用线程池使用线程池原因
1。复用已创建的线程,减少线程创建、销毁开销。2。可以根据自身系统的承载能力,合理对线程池线程数量进行控制。3。控制并发数,保护系统。privatestaticvoidcreatThreadPool()throwsInterruptedException{ListThreadthreadListnewArrayList();longstartSystem。currentTimeMillis();log。info(创建线程池开始);for(inti0;i100;i){ThreadthreadnewThread((){try{TimeUnit。SECONDS。sleep(10);}catch(InterruptedExceptione){e。printStackTrace();}},threadi);thread。start();threadList。add(thread);TimeUnit。MILLISECONDS。sleep(1);}longendSystem。currentTimeMillis();longneedTimeendstart;log。info(创建100个线程所花费的时间:needTimems);}publicstaticvoidmain(String〔〕args)throwsInterruptedException{creatThreadPool();}复制代码
创建100个线程需要264ms,平均一个线程的创建需要2。2ms左右,线程执行任务可以只需要不到1ms,那么这样看来创建线程是不划算的。
这里除里JDK自带的四种线程池类型,简单介绍下jdk自带四种线程池。
1。newCachedThreadPool:可缓存的的无界线程池,可以自动线程回收,通常执行短期异步的任务。
2。newFixThreadPool:固定数量的线程池,控制并发数。
3。newSingleThreadPool:单线程工作的线程池,所有任务按照FIFO先进先出的原则执行。
4。newScheduleThreadPool:可定期执行的线程池,可指定执行时间和执行次数。
通常情况下,在阿里的开发手册上写不推荐使用Executors创建线程,也就是线程池的顶级接口,jdk自带的线程池创建的时候是没有核心线程数的,不断的创建对象,那么就会存在内存溢出的风险。线程池的工作流程
一般创建线程池还是使用ThreadPoolExecutor创建,它的上接口是ExecutorService,所有说真正创建线程池是用ExecutorService创建。7大核心参数这里就不多说了,直接说线程池的工作流程。
1。首先当运行的线程池corePoolSize(核心线程数),就会创建线程执行这个任务
2。线程池线程数corePoolSize(核心线程数),任务放入队列。
3。队列已满,当前运行的线程数MaxImumPoolSize(最大线程数),创建非核心线程数执行任务,如果运行的线程数MaxImumPoolSize(最大线程数),使用Handler拒绝策略,当然不能丢弃任务,一般使用CallerRunsPolicy使用调用线程执行任务。
4。当前线程不需要执行任务,也不能让它一直存在着占用资源,超出keepAliveTime,运行线程数corePoolSize,这线程会被回收掉,这样做主要是控制核心线程里线程数量。线程复用
首先看ThreadPoolExecutor源码,execute线程池执行入口publicvoidexecute(Runnablecommand){if(commandnull)thrownewNullPointerException();当前线程数小于核心线程数intcctl。get();if(workerCountOf(c)corePoolSize){if(addWorker(command,true))return;cctl。get();}加入等待队列里排队处理if(isRunning(c)workQueue。offer(command)){intrecheckctl。get();检查工作线程停止工作是否需要移除,触发拒绝策略if(!isRunning(recheck)remove(command))reject(command);二次检查elseif(workerCountOf(recheck)0)addWorker(null,false);}无法提交线程则触发拒绝策略elseif(!addWorker(command,false))reject(command);}复制代码
这里看到每个if判断里都存在addWorker方法,那么这个方法肯定是线程是否复用的重点,Workerwnull;try{将任务放到Worker工作线程里面,wnewWorker(firstTask);finalThreadtw。thread;if(t!null){finalReentrantLockmainLockthis。mainLock;mainLock。lock();try{Recheckwhileholdinglock。BackoutonThreadFactoryfailureorifshutdownbeforelockacquired。intrsrunStateOf(ctl。get());if(rsSHUTDOWN(rsSHUTDOWNfirstTasknull)){if(t。isAlive())precheckthattisstartablethrownewIllegalThreadStateException();hashset集合里存放Worker对象workers。add(w);intsworkers。size();if(slargestPoolSize)largestPoolSizes;workerAddedtrue;}}finally{mainLock。unlock();}if(workerAdded){t。start();workerStartedtrue;}}}finally{if(!workerStarted)addWorkerFailed(w);}returnworkerStarted;复制代码
Worker是个final修饰的内部类,意味着不能被其他类继承,那么线程复用只能在这一个类里面进行,接着看Worker的run方法里面执行的runWorker方法,这个是线程复用的核心方法。finalvoidrunWorker(Workerw){ThreadwtThread。currentThread();获取线程里面执行的任务Runnabletaskw。firstTask;w。firstTasknull;w。unlock();allowinterruptsbooleancompletedAbruptlytrue;try{如果任务不为空重新拿取线程里的任务while(task!null(taskgetTask())!null){w。lock();Ifpoolisstopping,ensurethreadisinterrupted;ifnot,ensurethreadisnotinterrupted。ThisrequiresarecheckinsecondcasetodealwithshutdownNowracewhileclearinginterrupt判断线程的状态,并执行对应的拒绝策略if((runStateAtLeast(ctl。get(),STOP)(Thread。interrupted()runStateAtLeast(ctl。get(),STOP)))!wt。isInterrupted())wt。interrupt();try{beforeExecute(wt,task);Throwablethrownnull;try{task。run();}catch(RuntimeExceptionx){thrownx;throwx;}catch(Errorx){thrownx;throwx;}catch(Throwablex){thrownx;thrownewError(x);}finally{afterExecute(task,thrown);}}finally{tasknull;w。completedTasks;w。unlock();}}completedAbruptlyfalse;}finally{processWorkerExit(w,completedAbruptly);}复制代码
getTask方法重新拿取线程里的任务,前面一系列的判断主要是来检查线程的状态,以及线程池线程的数量,其核心主要是线程数量是否超过了核心线程数,如果超过了则会进入workQueue工作队列,workQueue。poll非核心线程会一直去工作队列里获取任务,非核心线程已经满了,则会workQueue。take()核心线程去获取任务,前面的runWorker方法是有while循环的,这样就会一直执行下去,循环拿取任务,如果这个时候工作队列里面没有队列,超过keepAliveTime线程存活时间还没有拿到任务,则会对对应线程进行销毁。privateRunnablegetTask(){booleantimedOutfalse;Didthelastpoll()timeout?for(;;){intcctl。get();intrsrunStateOf(c);Checkifqueueemptyonlyifnecessary。if(rsSHUTDOWN(rsSTOPworkQueue。isEmpty())){decrementWorkerCount();returnnull;}intwcworkerCountOf(c);Areworkerssubjecttoculling?booleantimedallowCoreThreadTimeOutwccorePoolSize;if((wcmaximumPoolSize(timedtimedOut))(wc1workQueue。isEmpty())){if(compareAndDecrementWorkerCount(c))returnnull;continue;}try{Runnablertimed?workQueue。poll(keepAliveTime,TimeUnit。NANOSECONDS):workQueue。take();if(r!null)returnr;timedOuttrue;}catch(InterruptedExceptionretry){timedOutfalse;}}}复制代码总结
在日常开发中,对线程池的优化也是比较重要的,如果线程池的核心线程数和最大线程数都不是随意定义的,还是要结合本身服务器cpu的情况,以及阻塞队列的使用,在一定情况下能缓解线程的压力,本身阻塞队列是带有阻塞和唤醒的功能,阻塞队列的长度也是需要根据实际开大的业务场景去定义的,最后运用好线程池,在处理高并发的业务场景下还是尤为关键的一项技术。
白宫想让NFT空间更环保白宫上周发布的一份报告呼吁所有区块链采取措施,使其更加环保。NFT已被选为区块链世界中一个特别耗能的角落。虽然不可替代代币本身不会对环境造成任何影响,但生产它们所需的能源却会。大多
恩施街,不一样的烟火没有什么能够阻挡,人们对美食的钟爱。在青山区恩施街,傍晚六点不到,分布在道路两旁的各色餐饮店门口就已经开始有人排队等座。在抖音上看到恩施街的美味,专门赶过来尝尝鲜。家住汉口常青花园
藏在深闺无人知的港珠澳大桥早有打算去大名鼎鼎的港珠澳大桥看看,这不仅是它运用的科技和创新项目之多,造价之高举世无双,更重要的是它有许多的世界第一,是粤港澳大湾区的一个宝。去年国庆期间,我有机会去了一趟珠海,
1985年梁兴初去世,妻子任桂兰提出唯一请求,中央立刻批示同意如果您喜欢这篇作品,欢迎点击右上方关注。感谢您的鼓励与支持,希望能给您带来舒适的阅读体验。1985年9月,梁兴初因突发心脏病,抢救无效后遗憾离世。在他去世后,他的妻子任桂兰悲痛不已
神舟十四号航天员乘组将于近日择机实施第二次出舱活动IT之家9月16日消息,据中国载人航天工程办公室消息,神舟十四号航天员乘组将于近日择机实施第二次出舱活动。自2022年9月2日圆满完成首次出舱活动以来,神舟十四号航天员乘组先后完成
THE9许佳琪生日晒合影,四位成员出镜,赵小棠僵硬,她完全认不出今年出道的女团里面,THE9是势头比较猛的,不知道是不是因为刚好大家都在放假,今年的青你2格外的火,不管是热搜上面,还是每一位成员的话题度,在节目播出期间,热度一直居高不下。最后在
翻车比火还快?羊了个羊,是对行业认真做游戏的人的侮辱羊了个羊,火出圈了!它是怎么火的,游戏公司狂砸钱买营销。通过达人们的试玩视频,带火热度,算法推荐网友吐槽讨论游戏通关率0。1通关的人智商都超过180之类的宣传,又成功带火了话题。于
吴亦凡李易峰接连暴雷,王思聪为什么没有翻车?作为曝光率不低的半个娱乐圈人物,号称娱乐圈纪检委书记的王思聪,为什么这么多年没有翻车?吴亦凡李易峰接连翻车,观众目不暇接,但曝光率不低于这些明星的首富二代王思聪,为什么这么多年先走
8位翻车明星现状李易峰年收入过亿,李小璐住千万豪宅头条创作挑战赛近年来,娱乐圈翻车明星越来越多,偷逃税,嫖娼,吸毒,出轨,个个令人失望,这些行为也让他们断送了娱乐圈的大好前程,不过他们虽然不能再做明星,但却是名副其实的富豪,生活还
为什么武功山会有一个绝望坡,它究竟有多难走?绝望坡是萍乡市芦溪县境内武功山风景区的一段山路,在金顶景区和发云界景区之间,因坡度大,坡路长而得名。绝望坡陡路长坡陡,不免使人绝望。还没走几步,大家可能都会觉得非常的累了。这里路长
国庆去哪儿玩?宁波版稻城亚丁,一定要来看的绿野蓝海我不信谁会没有川西梦,高山草甸绿野蓝海。是一直想放飞自由的信仰,也是走遍祖国山河迫不及待的美景。不过疫情当下,如果阻挡了出游的脚步,不要慌!你可以看看属于宁波的这些景,家门口的稻城