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