摘要:當(dāng)線程池執(zhí)行一個(gè)任務(wù)集合時(shí),它也會(huì)持有一些基本的統(tǒng)計(jì)數(shù)據(jù),例如完成任務(wù)的數(shù)量。當(dāng)命令以超過隊(duì)列所能處理的平均數(shù)連續(xù)到達(dá)時(shí),此策略允許無界線程具有增長(zhǎng)的可能性?;厥债?dāng)線程池在程序中不在被引用并且不再持有線程,將會(huì)自動(dòng)關(guān)閉。
概要
線程池主要解決兩個(gè)問題:當(dāng)執(zhí)行多個(gè)異步任務(wù)時(shí),可以實(shí)驗(yàn)線程池來提高性能,因?yàn)槭褂镁€程池可以減少了每個(gè)任務(wù)的調(diào)用開銷,并且提供了限制和管理資源的方式,例如線程資源。當(dāng)線程池執(zhí)行一個(gè)任務(wù)集合時(shí),它也會(huì)持有一些基本的統(tǒng)計(jì)數(shù)據(jù),例如完成任務(wù)的數(shù)量。為了能夠在廣泛的環(huán)境中可用,這個(gè)類提供了很多可調(diào)整的參數(shù)和一些可擴(kuò)展的鉤子。然而程序員都更加喜歡使用一些工廠方法:Executors#newCachedThreadPool(無界線程池并且線程可自動(dòng)回收)、Executors#newFixedThreadPool(固定大小的線程池)、Executors#newSingleThreadExecutor(單個(gè)后臺(tái)線程),這些工廠已經(jīng)預(yù)配置的最常用的場(chǎng)景,你也可以手動(dòng)的按照如下的指南配置和調(diào)整這個(gè)類:
ThreadPoolExecutor可以根據(jù)核心線程數(shù)和最大線程數(shù)自動(dòng)調(diào)整池的大小。
當(dāng)調(diào)用方法execute(Runable)提交一個(gè)新的任務(wù)時(shí):
如果正在運(yùn)行的線程數(shù)小于corePoolSize:
創(chuàng)建一個(gè)新的線程處理請(qǐng)求,即使其他的工作線程處于空閑狀態(tài)。
如果正在運(yùn)行的線程數(shù)大于corePoolSize但是小于maximumPoolSize:
只有隊(duì)列滿時(shí)才會(huì)重新創(chuàng)建一個(gè)新的線程。
通過設(shè)置corePoolSize=maximumPoolSize,你可以創(chuàng)建一個(gè)大小固定的線程池。
通過設(shè)置maximumPoolSize為一個(gè)無窮大數(shù)值(例如Integer.MAX_VALUE),那么說明你配置的線程池可以容納任意數(shù)量的并發(fā)任務(wù)。
一般情況下,corePoolSize和maximumPoolSize都會(huì)在創(chuàng)建的時(shí)候指定的,但是你們也可以通過調(diào)用setCorePoolSize()和setMaximumPoolSize()來動(dòng)態(tài)的調(diào)整這兩個(gè)值。
默認(rèn)情況下,核心線程只有當(dāng)任務(wù)到達(dá)時(shí)才會(huì)進(jìn)行創(chuàng)建和開啟,但是可以重寫方法`prestartCoreThread`或者`prestartAllCoreThreads`改變這個(gè)行為。如果你構(gòu)建的線程池帶有一個(gè)非空的隊(duì)列,你可能需要提前開啟一些線程。
創(chuàng)建新的線程:
新的線程是通過使用ThreadFactory來創(chuàng)建的,如果沒有指定的話,就會(huì)使用默認(rèn)的Executors#defaultThreadFactory,這個(gè)默認(rèn)的工廠創(chuàng)建出的線程都具有相同的ThreadGroup和相同的優(yōu)先級(jí)并且都不是后臺(tái)線程。通過實(shí)現(xiàn)一個(gè)不同的線程工廠,你可以修改線程的名字、線程組、優(yōu)先級(jí)、后臺(tái)狀態(tài)等等。如果ThreadFactory在從newThread中返回null時(shí)未能創(chuàng)建線程,則執(zhí)行程序?qū)⒗^續(xù),但可能無法執(zhí)行任何任務(wù)。線程應(yīng)該具有修改線程的權(quán)限。如果工作線程或者其他線程使用線程池是不具有這個(gè)權(quán)限,服務(wù)可以會(huì)被降級(jí):配置改變可能無法及時(shí)生效,and a shutdown pool may remain in a* state in which termination is possible but not completed。
如果線程池有超過corePoolSize數(shù)的線程數(shù),如果這些過量的線程空閑時(shí)間超過`keepAliveTime`將會(huì)被終止。當(dāng)線程池沒有被使用充分時(shí),這種機(jī)制可以降低資源的消耗。當(dāng)線程池之后又變得活躍起來,新的線程又會(huì)被創(chuàng)建。這個(gè)參數(shù)可以被動(dòng)態(tài)的改變,使用`setKeepAliveTime(long,TimeUnit)`。通過使用`Integer.MAX_VALUE`可以有效的禁用此功能。默認(rèn)情況下,只有當(dāng)前的線程數(shù)大于corePoolSize,這個(gè)策略才會(huì)生效。但是方法`allowCoreThreadTimeOut(boolean)`也能夠?qū)⒑诵木€程使用這種策略,只要`keepAliveTime`非0即可。
任何`BlockingQueue`都可以用來傳輸和保存提交的任務(wù),此隊(duì)列的使用和線程池大小有如下的交互:
如果運(yùn)行的線程數(shù)量小于corePoolSize:
Executor會(huì)創(chuàng)建一個(gè)新的線程而不是添加到隊(duì)列中。
如果允許的線程數(shù)量大于corePoolSize:
Executor會(huì)將任務(wù)添加到隊(duì)列中而不是創(chuàng)建一個(gè)新的線程。
如果一個(gè)請(qǐng)求不能添加到隊(duì)列中(隊(duì)列已滿),如果允許的線程小于maximumPoolSize,將會(huì)創(chuàng)建一個(gè)新的線程,否則,該任務(wù)將會(huì)被拒絕。
隊(duì)列有三種常見的策略:
直接提交: 它將任務(wù)直接提交給線程而不保存它們。在此,如果不存在可用于立即運(yùn)行任務(wù)的線程,則試圖把任務(wù)加入隊(duì)列將失敗,因此會(huì)構(gòu)造一個(gè)新的線程。此策略可以避免在處理可能具有內(nèi)部依賴性的請(qǐng)求集時(shí)出現(xiàn)鎖。直接提交通常要求無界 maximumPoolSizes 以避免拒絕新提交的任務(wù)。當(dāng)命令以超過隊(duì)列所能處理的平均數(shù)連續(xù)到達(dá)時(shí),此策略允許無界線程具有增長(zhǎng)的可能性。 SynchronousQueue線程安全的Queue,可以存放若干任務(wù)(但當(dāng)前只允許有且只有一個(gè)任務(wù)在等待),其中每個(gè)插入操作必須等待另一個(gè)線程的對(duì)應(yīng)移除操作,也就是說A任務(wù)進(jìn)入隊(duì)列,B任務(wù)必須等A任務(wù)被移除之后才能進(jìn)入隊(duì)列,否則執(zhí)行異常策略。你來一個(gè)我扔一個(gè),所以說SynchronousQueue沒有任何內(nèi)部容量。關(guān)于SynchronousQueue:http://blog.csdn.net/yanyan19...
無界隊(duì)列:使用一個(gè)沒有提前預(yù)設(shè)容量的無界的隊(duì)列,例如:LinkedBlockingQueue,當(dāng)所有的核心線程處于繁忙時(shí),所有新的任務(wù)都會(huì)被添加到隊(duì)列中。因此如果運(yùn)行線程數(shù)不超過corePoolSize,將會(huì)創(chuàng)建一個(gè)新的線程(maximumPoolSize這個(gè)值將不會(huì)再起作用),當(dāng)每個(gè)任務(wù)完全獨(dú)立于其他任務(wù)時(shí),這可能是合適的,因此任務(wù)不能影響彼此的執(zhí)行。在一個(gè)網(wǎng)頁服務(wù)器。雖然這種排隊(duì)方式可以有效地消除瞬時(shí)突發(fā)請(qǐng)求,但是當(dāng)命令以比它們可以被處理的速度更快地平均到達(dá)時(shí),可能會(huì)導(dǎo)致無限制的工作隊(duì)列增長(zhǎng)。
有界隊(duì)列:有限的隊(duì)列(例如,ArrayBlockingQueue)有助于防止與有限的maximumPoolSizes一起使用時(shí)的資源耗盡,但可能更難以調(diào)整和控制。 隊(duì)列大小和最大池大小可以相互交換:使用大隊(duì)列和小池可以最大限度地減少CPU使用率,操作系統(tǒng)資源和上下文切換開銷,但可能導(dǎo)致人為的低吞吐量。 如果任務(wù)經(jīng)常阻塞(例如,如果它們是I / O型操作),則系統(tǒng)可能能夠安排時(shí)間來獲得比您允許的更多的線程。 使用小隊(duì)列通常需要更大的池大小,這會(huì)使CPU更繁忙,但可能會(huì)遇到不可接受的調(diào)度開銷,這也會(huì)降低吞吐量。
當(dāng)Executor已經(jīng)被關(guān)閉時(shí),再調(diào)用`execute(Runable)`方法添加一個(gè)任務(wù)時(shí)將會(huì)被拒絕,當(dāng)Executor使用有界隊(duì)列時(shí),隊(duì)列和最大線程數(shù)都已經(jīng)飽和,將會(huì)調(diào)RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)方法。提供4種預(yù)定義的處理器:
ThreadPoolExecutor.AbortPolicy:該處理器拋出一個(gè)運(yùn)行時(shí)異常RejectedExecutionException。
ThreadPoolExecutor.CallerRunsPolicy:使用調(diào)用者自己的線程運(yùn)行任務(wù)。 提供了一個(gè)簡(jiǎn)單的反饋控制機(jī)制,可以減慢提交新任務(wù)的速度。
ThreadPoolExecutor.DiscardPolicy:丟棄任務(wù)。
ThreadPoolExecutor.DiscardOldestPolicy:如果executor還沒有被關(guān)閉,隊(duì)列頭部的任務(wù)將會(huì)被丟棄,并且重新執(zhí)行(可能再一次失敗,但是會(huì)重復(fù)執(zhí)行)
你可以定義并使用其他的實(shí)現(xiàn)自RejectedExecutionHandler的類。要做到這一點(diǎn)需要特別注意,特別是在策略僅在特定能力或排隊(duì)政策下工作的情況下。
這個(gè)類提供一寫被protected修飾的方法:
beforeExecute(Thread, Runnable),afterExecute(Runnable, Throwable)
這些方法會(huì)在每個(gè)任務(wù)執(zhí)行之前和執(zhí)行之后被調(diào)用,這些可以用來操作執(zhí)行環(huán)境;例如:重新初始化ThreadLocals,收集統(tǒng)計(jì)數(shù)據(jù),或者添加log。另外,terminated也可以被重寫當(dāng)執(zhí)行程序完全終止后需要執(zhí)行的特殊處理。
如果鉤子或者callback方法拋出異常,內(nèi)部工作線程可能會(huì)失敗并突然終止。
方法`getQueue()`運(yùn)行訪問工作隊(duì)列以此來進(jìn)行監(jiān)控和調(diào)試。強(qiáng)烈建議不要將這種方法用于任何其他目的。當(dāng)大量的排隊(duì)的任務(wù)被取消時(shí),兩個(gè)提供的方法`remove()`和`purge()`可用來幫助存儲(chǔ)回收。
當(dāng)線程池在程序中不在被引用并且不再持有線程,將會(huì)自動(dòng)關(guān)閉。如果你希望確保即使用戶忘記調(diào)用`shutdown()`也可以回收未引用的線程池,那么必須設(shè)置適當(dāng)?shù)谋3只顒?dòng)的時(shí)間,使用0核心線程的下限來安排未使用的線程最終死亡或設(shè)置`allowCoreThreadTimeOut(boolean)`問題?
隊(duì)列中的三種策略中,直接提交的工作原理是怎么樣的?
如何擴(kuò)展ThreadPoolExecutors?
線程池的工作原理是怎么樣的?如何提交一個(gè)任務(wù)?如何處理一個(gè)任務(wù)?
創(chuàng)建一個(gè)線程的流程?
?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68153.html
摘要:而是在初始化時(shí),在讀取了監(jiān)聽的數(shù)據(jù)的值之后,便立即調(diào)用一遍你設(shè)置的監(jiān)聽回調(diào),然后傳入剛讀取的值設(shè)置了時(shí),如何工作我們都知道有一個(gè)選項(xiàng),是用來深度監(jiān)聽的。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下...
摘要:原理剖析第篇工作原理分析一大致介紹相信大家都用過線程池,對(duì)該類應(yīng)該一點(diǎn)都不陌生了我們之所以要用到線程池,線程池主要用來解決線程生命周期開銷問題和資源不足問題我們通過對(duì)多個(gè)任務(wù)重用線程以及控制線程池的數(shù)目可以有效防止資源不足的情況本章節(jié)就著 原理剖析(第 003 篇)ThreadPoolExecutor工作原理分析 - 一、大致介紹 1、相信大家都用過線程池,對(duì)該類ThreadPoolE...
摘要:互聯(lián)網(wǎng)信息爆發(fā)式增長(zhǎng)時(shí)代,要想做好就必須簡(jiǎn)單了解搜索引擎基本工作原理以及自然排名機(jī)制搜索引擎工作過程是非常復(fù)雜,冬鏡在本章介紹的內(nèi)容相對(duì)于真正的搜索引擎技術(shù)來說僅僅是皮毛不過對(duì)新手已經(jīng)足夠用了,我盡量以最容易理解的方式來講解一搜索引擎蜘蛛搜互聯(lián)網(wǎng)信息爆發(fā)式增長(zhǎng)時(shí)代,要想做好SEO就必須簡(jiǎn)單了解搜索引擎基本工作原理以及自然排名機(jī)制搜索引擎工作過程是非常復(fù)雜,冬鏡SEO在本章介紹的內(nèi)容相對(duì)于真正...
摘要:原理剖析第篇工作原理分析一大致介紹關(guān)于多線程競(jìng)爭(zhēng)鎖方面,大家都知道有個(gè)和,也正是這兩個(gè)東西才引申出了大量的線程安全類,鎖類等功能而隨著現(xiàn)在的硬件廠商越來越高級(jí),在硬件層面提供大量并發(fā)原語給我們層面的開發(fā)帶來了莫大的利好本章節(jié)就和大家分享分 原理剖析(第 004 篇)CAS工作原理分析 - 一、大致介紹 1、關(guān)于多線程競(jìng)爭(zhēng)鎖方面,大家都知道有個(gè)CAS和AQS,也正是這兩個(gè)東西才引申出了大...
摘要: 徹底理解ESLint。 原文:ESLint 工作原理探討 作者:zhangwang Fundebug經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有。 ESLint 可謂是現(xiàn)代前端開發(fā)過程中必備的工具了。其用法簡(jiǎn)單,作用卻很大,使用過程中不知曾幫我減少過多少次可能的 bug。其實(shí)仔細(xì)想想前端開發(fā)過程中的必備工具似乎也沒有那么多,ESLint 做為必備之一,值得深挖,理解其工作原理。 在正式討論原理...
閱讀 850·2023-04-25 16:55
閱讀 2913·2021-10-11 10:59
閱讀 2154·2021-09-09 11:38
閱讀 1887·2021-09-03 10:40
閱讀 1544·2019-08-30 15:52
閱讀 1214·2019-08-30 15:52
閱讀 1037·2019-08-29 15:33
閱讀 3555·2019-08-29 11:26