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