摘要:線程池為了節省系統在多線程并發時不斷創建和銷毀線程帶來的額外開銷,就需要引入線程池。其中表示一個線程池。表示一個線程工廠,通過可以取得一個特定功能的線程池。創建固定數目線程的線程池。默認情況下,在創建了線程池后,線程池中的線程數為。
【線程池
為了節省系統在多線程并發時不斷創建和銷毀線程帶來的額外開銷,就需要引入線程池。線程池的基本功能就是進行線程的復用。當系統接受一個提交的任務時,并不會著急去創建一個新的線程去執行這個任務,而是去線程池中查詢是否有空閑的線程。
若有:直接使用這個線程。
若沒有:根據配置的策略執行(有可能時創建一個新的線程,也有可能是阻塞該任務等待空閑線程)。待任務結束之后,也不會銷毀線程,而是放入線程池的空閑隊列,等待下次使用。
【executor框架為了能更好的控制多線程,jdk提供了一套executor框架。其中ThreadPoolExecutor表示一個線程池。Executors表示一個線程工廠,通過Executors可以取得一個特定功能的線程池。
public static ExecutorService newFixedThreadPool(int nThreads)
創建固定數目線程的線程池。
public static ExecutorService newCachedThreadPool()
創建一個可緩存的線程池,調用execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。
public static ExecutorService newSingleThreadExecutor()
創建一個單線程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
創建一個支持定時及周期性的任務執行的線程池,多數情況下可用來替代Timer類。
但是這些工廠方法最后都是使用的ThreadPoolExecutor這個類。
【ThreadPoolExecutor參數含義- corePoolSize:核心池的大小,這個參數跟后面講述的線程池的實現原理有非常大的關系。在創建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務到來才創建線程去執行任務,除非調用prestartAllCoreThreads()或者prestartCoreThread()方法。從這2個方法的名字就可以看出,是預創建線程的意思,即在沒有任務到來之前就創建corePoolSize個線程或者一個線程。默認情況下,在創建了線程池后,線程池中的線程數為0。當有任務來之后,就會創建一個線程去執行任務,當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中; - maximumPoolSize:線程池最大線程數,這個參數也是一個非常重要的參數,它表示在線程池中最多能創建多少個線程; - keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。默認情況下,只有當線程池中的線程數大于corePoolSize時,keepAliveTime才會起作用。直到線程池中的線程數不大于corePoolSize,即當線程池中的線程數大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。 但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大于corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0; - unit:參數keepAliveTime的時間單位 - workQueue:一個阻塞隊列,用來存儲等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這里的阻塞隊列有以下幾種選擇: ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue; - threadFactory:線程工廠,主要用來創建線程; - handler:表示當拒絕處理任務時的策略,有以下四種取值: - ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出 RejectedExecutionException異常。 - ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。 - ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程) - ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務【現在重點講講workQueue
參數workQueue是指被提交但未執行的任務隊列,他是一個BlockingQueue接口的對象,僅用于存放runnable對象。根據隊列功能分類,在ThreadPoolExecutor構造參數中可以使用以下幾種BlockingQueue:
- 直接提交隊列:SynchronousQueue對象提供。SynchronousQueue是一個特殊的BlockingQueue,SynchronousQueue沒有容量,不保存任務他總是將任務提交給線程執行,如果沒有空閑的線程就會嘗試創建新的線程。如果線程數達到maximumPoolSize,則執行拒絕策略。因此使用SynchronousQueue通常會設置很大的maximumPoolSize,否則容易執行拒絕策略。 - 有界任務隊列:有界任務隊列可以使用ArrayBlockingQueue實現,其構造函數必須帶一個參數表示最大容量。當使用有界任務隊列的時候:如果有新任務提交,若線程數小于corePoolSize,則會優先創建新的線程,若大于corePoolSize則會將任務置于等待隊列中,如果等待隊列已滿,在線程數小于maximumPoolSize時,會創建新的線程執行任務,否則執行拒絕策略。最終,除非系統非常繁忙,否則線程數將會維持在corePoolSize。 - 無界任務隊列:無界任務隊列可以通過LinkedBlockingQueue類實現。與有界隊列相比,除非系統資源耗盡,否則無界任務隊列不存在任務入隊失敗的情況。當有新任務提交的時候:如果系統線程小于corePoolSize,會創建新的線程執行任務,如果大于corePoolSize則不會增加新的線程,任務會進入等待隊列,無界隊列會持續增長,直到系統資源耗盡。 - 優先任務隊列:帶有執行優先級的隊列,通過PriorityBlockingQueue實現,可以控制任務執行順序特殊的無界隊列。無論有界還是無界隊列,都是fifo的執行任務,但是優先級任務隊列可以根據任務自身的優先級決定任務執行順序,在確保了性能的同時,也能保證執行質量(高優先級任務先執行)。【線程池如何復用線程
我們知道線程池會復用線程,但是它的內部邏輯是如何將一個Runnable對象賦值給Thread的呢?
1.線程池內部維護的不是Thread對象而是一個內部類Worker:
它繼承了AbstractQueuedSynchronizer類,實現了一個非重入的鎖。該鎖會保護一個正在等待任務被執行的Worker不被interrupt操作打斷。為什么不用ReentrantLock,要用非重入的鎖?因為作者不想讓這個Worker task在setCorePoolSize這種線程池控制方法調用時能重新獲取到鎖。當提交一個任務時,如果需要創建一個線程(何時需要在下一節中探討)時,就調用線程工廠創建一個線程,同時將線程綁定到Worker工作隊列中。需要說明的是,Worker隊列構造的時候帶著一個任務Runnable,因此Worker創建時總是綁定著一個待執行任務。換句話說,創建線程的前提是有必要創建線程,不會無緣無故創建一堆空閑線程等著任務。這是節省資源的一種方式。
2.線程重用:線程重用的核心是,它把Thread.start()給屏蔽起來了(一定不要重復調用),然后它自己有一個Runnable.run(),循環在跑,跑的過程中不斷檢查我們是否有新加入的子Runnable對象,有就調一下我們的run(),其實就一個大run()把其它小run()#1,run()#2,...給串聯起來了,基本原理就這么簡單。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68072.html
摘要:死亡狀態線程退出有可能是正常執行完成也有可能遇見異常退出。類有新建與死亡狀態返回其余狀態返回判斷線程是否存活。線程因某些原因進入阻塞狀態。執行同步代碼塊的過程中執行了當前線程放棄開始睡眠進入就緒狀態但是不會釋放鎖。 【java內存模型簡介 JVM中存在一個主存區(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對于所有線程進行共享,而每個...
摘要:一個線程池包含很多準備運行的空閑線程,每當執行完畢后,線程不會死亡而是回到線程池準備為下一個請求提供服務。另一個使用線程池的理由是減少并發線程數。創建大量線程會大大降低性能甚至拖垮虛擬機。 【Future的概念 interface Future ,表示異步計算的結果,Future有個get方法而獲取結果只有在計算完成時獲取,否則會一直阻塞直到任務轉入完成狀態,然后會返回結果或者拋出異常...
摘要:表示的是兩個,當其中任意一個計算完并發編程之是線程安全并且高效的,在并發編程中經常可見它的使用,在開始分析它的高并發實現機制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個比較典型的互聯網高并發場景。 干貨:深度剖析分布式搜索引擎設計 分布式,高可用,和機器學習一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個名詞,今天我們首先來說說分布式。 探究...
閱讀 3723·2021-11-24 10:23
閱讀 2770·2021-09-06 15:02
閱讀 1273·2021-08-23 09:43
閱讀 2350·2019-08-30 15:44
閱讀 3044·2019-08-30 13:18
閱讀 778·2019-08-23 16:56
閱讀 1742·2019-08-23 16:10
閱讀 535·2019-08-23 15:08