0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

線(xiàn)程數(shù)突增!領(lǐng)導(dǎo)說(shuō)再這么寫(xiě)就gc掉我

馬哥Linux運(yùn)維 ? 來(lái)源:馬哥Linux運(yùn)維 ? 2023-08-22 15:35 ? 次閱讀

前言

今天給大家分享一個(gè)線(xiàn)上問(wèn)題引出的一次思考,過(guò)程比較長(zhǎng),但是挺有意思。

今天上班把需求寫(xiě)完,出于學(xué)習(xí)(摸魚(yú))的心理上skywalking看看,突然發(fā)現(xiàn)我們的一個(gè)應(yīng)用,應(yīng)用內(nèi)線(xiàn)程數(shù)超過(guò)900條,接近1000條,但是cpu并沒(méi)有高漲,內(nèi)存也不算高峰。

但是敏銳的我還是立刻意識(shí)到這個(gè)應(yīng)用有不妥,因?yàn)榫€(xiàn)程數(shù)太多了,不符合我們一個(gè)正常健康的應(yīng)用數(shù)量。熟練的打出cpu dump觀察,首先看線(xiàn)程組名的概覽。

114ffb40-402e-11ee-ac96-dac502259ad0.jpg

從線(xiàn)程分組看,pool名開(kāi)頭線(xiàn)程占616條,而且waiting狀態(tài)也是616條,這個(gè)點(diǎn)就非??梢闪耍覕喽ň褪沁@個(gè)pool開(kāi)頭線(xiàn)程池導(dǎo)致的問(wèn)題。我們先排查為何這個(gè)線(xiàn)程池中會(huì)有600+的線(xiàn)程處于waiting狀態(tài)并且無(wú)法釋放,記接下來(lái)我們找?guī)讞l線(xiàn)程的堆棧觀察具體堆棧:

117816fc-402e-11ee-ac96-dac502259ad0.jpg

這個(gè)堆棧看上去很合理,線(xiàn)程在線(xiàn)程池中不斷的循環(huán)獲取任務(wù),因?yàn)楂@取不到任務(wù)所以進(jìn)入了waiting狀態(tài),等待著有任務(wù)后被喚醒。

看上去不只一個(gè)線(xiàn)程池,并且這些線(xiàn)程池的名字居然是一樣的,我大膽的猜測(cè)一下,是不斷的創(chuàng)建同樣的線(xiàn)程池,但是線(xiàn)程池?zé)o法被回收導(dǎo)致的線(xiàn)程數(shù),所以接下來(lái)我們要分析兩個(gè)問(wèn)題,首先這個(gè)線(xiàn)程池在代碼里是哪個(gè)線(xiàn)程池,第二這個(gè)線(xiàn)程池是怎么被創(chuàng)建的?為啥釋放不了?

我在idea搜索new ThreadPoolExecutor()得到的結(jié)果是這樣的:

118d472a-402e-11ee-ac96-dac502259ad0.jpg

于是我陷入懵逼的狀態(tài),難道還有其他騷操作?

正在這時(shí),一位不知名的鄭網(wǎng)友發(fā)來(lái)一張截圖:

11a77fe6-402e-11ee-ac96-dac502259ad0.jpg

好家伙!竟然是用new FixedTreadPool()整出來(lái)的。難怪我完全搜不到,因?yàn)橛玫?code style="margin-right:2px;margin-left:2px;padding:2px 4px;font-size:14px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(0,150,136);">new FixedTreadPool(),所以線(xiàn)程池中的線(xiàn)程名是默認(rèn)的pool(又多了一個(gè)不使用Executors來(lái)創(chuàng)建線(xiàn)程池的理由)。

然后我迫不及die的打開(kāi)代碼,試圖找到罪魁禍?zhǔn)?,結(jié)果發(fā)現(xiàn)作者居然是我自己。這是另一個(gè)驚喜,驚嚇的驚。

冷靜下來(lái)后我梳理一遍代碼,這個(gè)接口是我兩年前寫(xiě)的,主要是功能是統(tǒng)計(jì)用戶(hù)的錢(qián)包每個(gè)月的流水,因?yàn)閾?dān)心統(tǒng)計(jì)比較慢,所以使用了線(xiàn)程池,做了批量的處理,沒(méi)想到居然導(dǎo)致了線(xiàn)程數(shù)過(guò)高,雖然沒(méi)有導(dǎo)致事故,但是確實(shí)是潛在的隱患,現(xiàn)在沒(méi)出事不代表以后不會(huì)出事。

去掉多余業(yè)務(wù)邏輯,我簡(jiǎn)單的還原一個(gè)代碼給大家看,還原現(xiàn)場(chǎng):

privatestaticvoidthreadDontGcDemo(){
ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);
executorService.submit(()->{
System.out.println("111");
});
}

那么為啥線(xiàn)程池里面的線(xiàn)程和線(xiàn)程池都沒(méi)釋放呢。

難道是因?yàn)闆](méi)有調(diào)用shutdown?我大概能理解我兩年前當(dāng)時(shí)為啥不調(diào)用shutdown,是因?yàn)楫?dāng)初我覺(jué)得接口跑完,方法走到結(jié)束,理論上棧幀出棧,局部變量應(yīng)該都銷(xiāo)毀了,按理說(shuō)executorService這個(gè)變量應(yīng)該直接GG了,那么按理說(shuō)我是不用調(diào)用shutdown方法的。

我簡(jiǎn)單的跑了個(gè)demo,循環(huán)的去new線(xiàn)程池,不調(diào)用shutdown方法,看看線(xiàn)程池能不能被回收

11c124f0-402e-11ee-ac96-dac502259ad0.jpg

打開(kāi)java visual vm查看實(shí)時(shí)線(xiàn)程:

11ecc51a-402e-11ee-ac96-dac502259ad0.jpg

可以看到線(xiàn)程數(shù)和線(xiàn)程池都一直在增加,但是一直沒(méi)有被回收,確實(shí)符合發(fā)生的問(wèn)題狀況,那么假如我在方法結(jié)束前調(diào)用shutdown方法呢,會(huì)不會(huì)回收線(xiàn)程池和線(xiàn)程呢?

簡(jiǎn)單寫(xiě)個(gè)demo結(jié)合jvisualvm驗(yàn)證下:

121f1574-402e-11ee-ac96-dac502259ad0.jpg

124f630a-402e-11ee-ac96-dac502259ad0.jpg

結(jié)果是線(xiàn)程和線(xiàn)程池都被回收了。也就是說(shuō),執(zhí)行了shutdown的線(xiàn)程池最后會(huì)回收線(xiàn)程池和線(xiàn)程對(duì)象。

我們知道,一個(gè)對(duì)象能不能回收,是看它到gc root之間有沒(méi)有可達(dá)路徑,線(xiàn)程池不能回收說(shuō)明到達(dá)線(xiàn)程池的gc root還是有可達(dá)路徑的。這里講個(gè)冷知識(shí),這里的線(xiàn)程池的gc root是線(xiàn)程,具體的gc路徑是thread->workers->線(xiàn)程池。

線(xiàn)程對(duì)象是線(xiàn)程池的gc root,假如線(xiàn)程對(duì)象能被gc,那么線(xiàn)程池對(duì)象肯定也能被gc掉(因?yàn)榫€(xiàn)程池對(duì)象已經(jīng)沒(méi)有到gc root的可達(dá)路徑了)。

那么現(xiàn)在問(wèn)題就轉(zhuǎn)為線(xiàn)程對(duì)象是在什么時(shí)候gc。

這位網(wǎng)友給了一個(gè)粗淺但是合理的解釋?zhuān)€(xiàn)程對(duì)象肯定不是在運(yùn)行中的時(shí)候被回收的,因?yàn)閖vm肯定不可能去回收一條在運(yùn)行中的線(xiàn)程,至少runnalbe狀態(tài)的線(xiàn)程jvm不可能去回收。

在stackoverflow上我找到了更準(zhǔn)確的答案:

126e1340-402e-11ee-ac96-dac502259ad0.jpg

A running thread is considered a so called garbage collection root and is one of those things keeping stuff from being garbage collected。

這句話(huà)的意思是,一條正在運(yùn)行的線(xiàn)程是gc root,注意,是正在運(yùn)行,這個(gè)正在運(yùn)行我先透露下,即使是waiting狀態(tài),也算正在運(yùn)行。這個(gè)回答的整體的意思是,運(yùn)行的線(xiàn)程是gc root,但是非運(yùn)行的線(xiàn)程不是gc root(可以被回收)。

現(xiàn)在比較清楚了,線(xiàn)程池和線(xiàn)程被回收的關(guān)鍵就在于線(xiàn)程能不能被回收,那么回到原來(lái)的起點(diǎn),為何調(diào)用線(xiàn)程池的shutdown方法能夠?qū)е戮€(xiàn)程和線(xiàn)程池被回收呢?難道是shutdown方法把線(xiàn)程變成了非運(yùn)行狀態(tài)嗎?

talk is cheap,show me the code

我們直接看看線(xiàn)程池的shutdown方法的源碼

publicvoidshutdown(){
finalReentrantLockmainLock=this.mainLock;
mainLock.lock();
try{
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown();//hookforScheduledThreadPoolExecutor
}finally{
mainLock.unlock();
}
tryTerminate();
}

privatevoidinterruptIdleWorkers(){
interruptIdleWorkers(false);
}

privatevoidinterruptIdleWorkers(booleanonlyOne){
finalReentrantLockmainLock=this.mainLock;
mainLock.lock();
try{
for(Workerw:workers){
Threadt=w.thread;
if(!t.isInterrupted()&&w.tryLock()){
try{
t.interrupt();
}catch(SecurityExceptionignore){
}finally{
w.unlock();
}
}
if(onlyOne)
break;
}
}finally{
mainLock.unlock();
}
}

我們從interruptIdleWorkers方法入手,這方法看上去最可疑,看到interruptIdleWorkers方法,這個(gè)方法里面主要就做了一件事,遍歷當(dāng)前線(xiàn)程池中的線(xiàn)程,并且調(diào)用線(xiàn)程的interrupt()方法,通知線(xiàn)程中斷,也就是說(shuō)shutdown方法只是去遍歷所有線(xiàn)程池中的線(xiàn)程,然后通知線(xiàn)程中斷。所以我們需要了解線(xiàn)程池里的線(xiàn)程是怎么處理中斷的通知的。

我們點(diǎn)開(kāi)worker對(duì)象,這個(gè)worker對(duì)象是線(xiàn)程池中實(shí)際運(yùn)行的線(xiàn)程,所以我們直接看worker的run方法,中斷通知肯定是在里面被處理了

//WOrker的run方法里面直接調(diào)用的是這個(gè)方法
finalvoidrunWorker(Workerw){
Threadwt=Thread.currentThread();
Runnabletask=w.firstTask;
w.firstTask=null;
w.unlock();//allowinterrupts
booleancompletedAbruptly=true;
try{
while(task!=null||(task=getTask())!=null){
w.lock();
//Ifpoolisstopping,ensurethreadisinterrupted;
//ifnot,ensurethreadisnotinterrupted.This
//requiresarecheckinsecondcasetodealwith
//shutdownNowracewhileclearinginterrupt
if((runStateAtLeast(ctl.get(),STOP)||
(Thread.interrupted()&&
runStateAtLeast(ctl.get(),STOP)))&&
!wt.isInterrupted())
wt.interrupt();
try{
beforeExecute(wt,task);
Throwablethrown=null;
try{
task.run();
}catch(RuntimeExceptionx){
thrown=x;throwx;
}catch(Errorx){
thrown=x;throwx;
}catch(Throwablex){
thrown=x;thrownewError(x);
}finally{
afterExecute(task,thrown);
}
}finally{
task=null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly=false;
}finally{
processWorkerExit(w,completedAbruptly);
}
}

這個(gè)runwoker屬于是線(xiàn)程池的核心方法了,相當(dāng)?shù)挠幸馑?,線(xiàn)程池能不斷運(yùn)作的原理就是這里,我們一點(diǎn)點(diǎn)看。

首先最外層用一個(gè)while循環(huán)套住,然后不斷的調(diào)用gettask()方法不斷從隊(duì)列中取任務(wù),假如拿不到任務(wù)或者任務(wù)執(zhí)行發(fā)生異常(拋出異常了)那就屬于異常情況,直接將completedAbruptly設(shè)置為true,并且進(jìn)入異常的processWorkerExit流程。

我們看看gettask()方法,了解下啥時(shí)候可能會(huì)拋出異常:

privateRunnablegetTask(){
booleantimedOut=false;//Didthelastpoll()timeout?

for(;;){
intc=ctl.get();
intrs=runStateOf(c);

//Checkifqueueemptyonlyifnecessary.
if(rs>=SHUTDOWN&&(rs>=STOP||workQueue.isEmpty())){
decrementWorkerCount();
returnnull;
}

intwc=workerCountOf(c);

//Areworkerssubjecttoculling?
booleantimed=allowCoreThreadTimeOut||wc>corePoolSize;

if((wc>maximumPoolSize||(timed&&timedOut))
&&(wc>1||workQueue.isEmpty())){
if(compareAndDecrementWorkerCount(c))
returnnull;
continue;
}

try{
Runnabler=timed?
workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS):
workQueue.take();
if(r!=null)
returnr;
timedOut=true;
}catch(InterruptedExceptionretry){
timedOut=false;
}
}
}

這樣很清楚了,拋去前面的大部分代碼不看,這句代碼解釋了gettask的作用:

Runnabler=timed?
workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS):
workQueue.take()

gettask就是從工作隊(duì)列中取任務(wù),但是前面還有個(gè)timed,這個(gè)timed的語(yǔ)義是這樣的:如果allowCoreThreadTimeOut參數(shù)為true(一般為false)或者當(dāng)前工作線(xiàn)程數(shù)超過(guò)核心線(xiàn)程數(shù),那么使用隊(duì)列的poll方法取任務(wù),反之使用take方法。

這兩個(gè)方法不是重點(diǎn),重點(diǎn)是poll方法和take方法都會(huì)讓當(dāng)前線(xiàn)程進(jìn)入time_waiting或者waiting狀態(tài)。而當(dāng)線(xiàn)程處于在等待狀態(tài)的時(shí)候,我們調(diào)用線(xiàn)程的interrupt方法,毫無(wú)疑問(wèn)會(huì)使線(xiàn)程當(dāng)場(chǎng)拋出異常!

也就是說(shuō)線(xiàn)程池的shutdownnow方法調(diào)用interruptIdleWorkers去對(duì)線(xiàn)程對(duì)象interrupt是為了讓處于waiting或者是time_waiting的線(xiàn)程拋出異常。

那么線(xiàn)程池是在哪里處理這個(gè)異常的呢?我們看runwoker中的調(diào)用的processWorkerExit方法,說(shuō)實(shí)話(huà)這個(gè)方法看著就像處理拋出異常的方法:

privatevoidprocessWorkerExit(Workerw,booleancompletedAbruptly){
if(completedAbruptly)//Ifabrupt,thenworkerCountwasn'tadjusted
decrementWorkerCount();

finalReentrantLockmainLock=this.mainLock;
mainLock.lock();
try{
completedTaskCount+=w.completedTasks;
workers.remove(w);
}finally{
mainLock.unlock();
}

tryTerminate();

intc=ctl.get();
if(runStateLessThan(c,STOP)){
if(!completedAbruptly){
intmin=allowCoreThreadTimeOut?0:corePoolSize;
if(min==0&&!workQueue.isEmpty())
min=1;
if(workerCountOf(c)>=min)
return;//replacementnotneeded
}
addWorker(null,false);
}
}

我們可以看到,在這個(gè)方法里有一個(gè)很明顯的workers.remove(w)方法,也就是在這里,這個(gè)w的變量,被移出了workers這個(gè)集合,導(dǎo)致worker對(duì)象不能到達(dá)gc root,于是workder對(duì)象順理成章的變成了一個(gè)垃圾對(duì)象,被回收掉了。

然后等到worker中所有的worker都被移出works后,并且當(dāng)前請(qǐng)求線(xiàn)程也完成后,線(xiàn)程池對(duì)象也成為了一個(gè)孤兒對(duì)象,沒(méi)辦法到達(dá)gc root,于是線(xiàn)程池對(duì)象也被gc掉了。寫(xiě)了挺長(zhǎng)的篇幅,我小結(jié)一下:

  • 線(xiàn)程池調(diào)用shutdownnow方法是為了調(diào)用worker對(duì)象的interrupt方法,來(lái)打斷那些沉睡中的線(xiàn)程(waiting或者time_waiting狀態(tài)),使其拋出異常

  • 線(xiàn)程池會(huì)把拋出異常的worker對(duì)象從workers集合中移除引用,此時(shí)被移除的worker對(duì)象因?yàn)闆](méi)有到達(dá)gc root的路徑已經(jīng)可以被gc掉了

  • 等到workers對(duì)象空了,并且當(dāng)前tomcat線(xiàn)程也結(jié)束,此時(shí)線(xiàn)程池對(duì)象也可以被gc掉,整個(gè)線(xiàn)程池對(duì)象成功釋放

最后總結(jié)

如果只是在局部方法中使用線(xiàn)程池,線(xiàn)程池對(duì)象不是bean的情況時(shí),記得要合理的使用shutdown或者shutdownnow方法來(lái)釋放線(xiàn)程和線(xiàn)程池對(duì)象,如果不使用,會(huì)造成線(xiàn)程池和線(xiàn)程對(duì)象的堆積。


聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10863

    瀏覽量

    211763
  • 堆棧
    +關(guān)注

    關(guān)注

    0

    文章

    182

    瀏覽量

    19761
  • 線(xiàn)程
    +關(guān)注

    關(guān)注

    0

    文章

    504

    瀏覽量

    19682

原文標(biāo)題:線(xiàn)程數(shù)突增!領(lǐng)導(dǎo)說(shuō)再這么寫(xiě)就gc掉我

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    socket 多線(xiàn)程編程實(shí)現(xiàn)方法

    在現(xiàn)代網(wǎng)絡(luò)編程中,多線(xiàn)程技術(shù)被廣泛應(yīng)用于提高服務(wù)器的并發(fā)處理能力。Socket編程是網(wǎng)絡(luò)通信的基礎(chǔ),而將多線(xiàn)程技術(shù)應(yīng)用于Socket編程,可以顯著提升服務(wù)器的性能。 多線(xiàn)程編程的基本概念 多線(xiàn)
    的頭像 發(fā)表于 11-12 14:16 ?358次閱讀

    明明說(shuō)的是25G信號(hào),你卻讓看12.5G的損耗?

    那一天,問(wèn)高速先生25G光模塊信號(hào)在主板上允許的損耗是多少,他們就告訴在12.5G要滿(mǎn)足大概7.3dB,當(dāng)時(shí)就懵了,明明說(shuō)的是25G
    的頭像 發(fā)表于 10-23 09:08 ?1107次閱讀
    明明<b class='flag-5'>我</b><b class='flag-5'>說(shuō)</b>的是25G信號(hào),你卻讓<b class='flag-5'>我</b>看12.5G的損耗?

    CPU線(xiàn)程和程序線(xiàn)程的區(qū)別

    CPU的線(xiàn)程與程序的線(xiàn)程在概念、作用、實(shí)現(xiàn)方式以及性能影響等方面存在顯著差異。以下是對(duì)兩者區(qū)別的詳細(xì)闡述,旨在深入探討這一技術(shù)話(huà)題。
    的頭像 發(fā)表于 09-02 11:18 ?1022次閱讀

    探索虛擬線(xiàn)程:原理與實(shí)現(xiàn)

    虛擬線(xiàn)程的引入與優(yōu)勢(shì) 在Loom項(xiàng)目之前,Java虛擬機(jī)(JVM)中的線(xiàn)程是通過(guò)java.lang.Thread類(lèi)型來(lái)實(shí)現(xiàn)的,這些線(xiàn)程被稱(chēng)為平臺(tái)線(xiàn)程。 然而,平臺(tái)
    的頭像 發(fā)表于 06-24 11:35 ?306次閱讀
    探索虛擬<b class='flag-5'>線(xiàn)程</b>:原理與實(shí)現(xiàn)

    esp32S3一進(jìn)入燒寫(xiě)就報(bào)錯(cuò)的原因?

    使用的是esp32S3,IDF v4.3,環(huán)境windows 10 前面的構(gòu)建都可以成功,但是一進(jìn)入燒寫(xiě)就會(huì)報(bào)錯(cuò): A fatal error occurred: This chip
    發(fā)表于 06-20 07:39

    鴻蒙開(kāi)發(fā):【線(xiàn)程模型】

    管理其他線(xiàn)程的ArkTS引擎實(shí)例,例如使用TaskPool(任務(wù)池)創(chuàng)建任務(wù)或取消任務(wù)、啟動(dòng)和終止Worker線(xiàn)程。
    的頭像 發(fā)表于 06-13 16:38 ?410次閱讀
    鴻蒙開(kāi)發(fā):【<b class='flag-5'>線(xiàn)程</b>模型】

    常見(jiàn)golang gc的內(nèi)部?jī)?yōu)化方案

    對(duì)這個(gè)優(yōu)化的描述印象最深的是在bigcache的注釋里,大致內(nèi)容是如果map的鍵值都不包含指針,那么gc掃描的時(shí)候不管這個(gè)map多大都不會(huì)深入掃描map內(nèi)部存儲(chǔ)的數(shù)據(jù),只檢查map本身是否需要回收。
    的頭像 發(fā)表于 03-29 11:19 ?507次閱讀

    Disable中斷之后Enable無(wú)法正常運(yùn)行是為什么?

    (EXTI2_3_IRQn); 這兩個(gè)注釋一個(gè)就無(wú)法實(shí)現(xiàn)功能。的問(wèn)題是:MX_GPIO_Init();函數(shù)里面有使能中斷語(yǔ)句了HAL_NVIC_EnableIRQ(EXTI2_3_IRQn); 為啥在if里面還得重復(fù)一遍這
    發(fā)表于 03-20 06:39

    java實(shí)現(xiàn)多線(xiàn)程的幾種方式

    Java實(shí)現(xiàn)多線(xiàn)程的幾種方式 多線(xiàn)程是指程序中包含了兩個(gè)或以上的線(xiàn)程,每個(gè)線(xiàn)程都可以并行執(zhí)行不同的任務(wù)或操作。Java中的多線(xiàn)程可以提高程序
    的頭像 發(fā)表于 03-14 16:55 ?709次閱讀

    python中5種線(xiàn)程鎖盤(pán)點(diǎn)

    線(xiàn)程安全是多線(xiàn)程或多進(jìn)程編程中的一個(gè)概念,在擁有共享數(shù)據(jù)的多條線(xiàn)程并行執(zhí)行的程序中,線(xiàn)程安全的代碼會(huì)通過(guò)同步機(jī)制保證各個(gè)線(xiàn)程都可以正常且正確
    發(fā)表于 03-07 11:08 ?1594次閱讀
    python中5種<b class='flag-5'>線(xiàn)程</b>鎖盤(pán)點(diǎn)

    什么是動(dòng)態(tài)線(xiàn)程池?動(dòng)態(tài)線(xiàn)程池的簡(jiǎn)單實(shí)現(xiàn)思路

    因此,動(dòng)態(tài)可監(jiān)控線(xiàn)程池一種針對(duì)以上痛點(diǎn)開(kāi)發(fā)的線(xiàn)程池管理工具。主要可實(shí)現(xiàn)功能有:提供對(duì) Spring 應(yīng)用內(nèi)線(xiàn)程池實(shí)例的全局管控、應(yīng)用運(yùn)行時(shí)動(dòng)態(tài)變更線(xiàn)程池參數(shù)以及
    的頭像 發(fā)表于 02-28 10:42 ?645次閱讀

    linux多線(xiàn)程編程實(shí)例

    linux線(xiàn)程
    的頭像 發(fā)表于 02-15 21:16 ?471次閱讀
    linux多<b class='flag-5'>線(xiàn)程</b>編程實(shí)例

    線(xiàn)程是什么的基本單位 進(jìn)程與線(xiàn)程的本質(zhì)區(qū)別

    線(xiàn)程是操作系統(tǒng)中處理器調(diào)度的基本單位,它代表著獨(dú)立的執(zhí)行流。在一個(gè)進(jìn)程中,可以包含多個(gè)線(xiàn)程,這些線(xiàn)程共享相同的進(jìn)程資源,如內(nèi)存空間、文件描述符等。 進(jìn)程是操作系統(tǒng)中運(yùn)行的程序的實(shí)例,它包含了程序
    的頭像 發(fā)表于 02-02 16:30 ?934次閱讀

    什么是守護(hù)線(xiàn)程?守護(hù)線(xiàn)程的底層原理和使用示例

    大家好,今天這篇文章來(lái)梳理一下有關(guān)守護(hù)線(xiàn)程的相關(guān)問(wèn)題,這也是之前曾經(jīng)有被問(wèn)到過(guò)的面試題,在此之前我們先看一看守護(hù)線(xiàn)程的使用示例。
    的頭像 發(fā)表于 01-05 11:01 ?1421次閱讀
    什么是守護(hù)<b class='flag-5'>線(xiàn)程</b>?守護(hù)<b class='flag-5'>線(xiàn)程</b>的底層原理和使用示例

    mcu線(xiàn)程和進(jìn)程的區(qū)別是什么

    MCU線(xiàn)程和進(jìn)程是嵌入式系統(tǒng)中常見(jiàn)的并行執(zhí)行的概念,它們之間有許多區(qū)別,包括線(xiàn)程與進(jìn)程的定義、資源管理、通信機(jī)制、執(zhí)行方式等等。下面將詳細(xì)介紹MCU線(xiàn)程和進(jìn)程的區(qū)別。 一、定義與概念 MCU線(xiàn)
    的頭像 發(fā)表于 01-04 10:45 ?753次閱讀