其他系列文章目錄
設計模式合集
多線程合集
分布式合集
ES合集
文章目錄
系列文章目錄
前言
一、為什么需要線程池?
二、舉個背景例子
三、怎么創建線程池?
四、線程池指定線程數
前言
學習線程池能夠幫助我們更好地處理多線程編程,并提高程序的性能和穩定性。
一、為什么需要線程池?
JVM在HotSpot的線程模型下,Java線程會一對一映射為內核線程。
這意味著,在Java中每次創建以及回收線程都會去內核創建以及回收。
這就有可能導致: 創建和銷毀線程所花費的時間和資源可能比處理的任務花費的時間和資源要更多。
線程池的出現是為了提高線程的復用性以及固定線程的數量!!!
二、舉個背景例子
一個消息管理平臺,提供其中一個功能就是: 運營會圈定人群然后群發消息。
主要流程大致就是:創建模板---->定時---->群發消息---->用戶收到消息。
先說一個概念:HDFS (Hadoop Distributed File System) 是分布式文件系統的一種,用于存儲和處理大數據集。它是Hadoop框架的核心組件之一。HDFS可以讓用戶將大數據集分散在多臺計算機上,以提高數據處理能力和可靠性。它將數據拆分為小塊并存儲在多臺計算機上,提供了讀寫分離、容錯機制、數據備份和高可用等特性。HDFS的基本單位是數據塊,通常為128MB或256MB。數據塊的復制數量和位置由系統自動管理。HDFS對于大數據的存儲和管理提供了高度的可靠性和可擴展性,因此被廣泛應用于大數據處理和分析領域。
然后運營圈定的人群實際上在模板上只是一個ID、這邊要通過ID去獲取到HDFS文件,
對HDFS文件進行遍歷,然后繼續往下發,(接收到定時任務,再對HDFS進行遍歷)這里的處理,用的就是線程池處理。
HDFS遍歷其實就是IO的操作,把這個過程給異步化,為了提高系統的吞吐量,于是這里用的線程池。即便遍歷HDFS出現問題,我們可以建設完備的監控和告警可以及時發現。
三、怎么創建線程池?
阿里巴巴開發手冊就有提到,不要使用Executors去創建線程。建議使用ThreadPoolExecutor去創建線程池。
最主要的目的就是:使用ThreadPoolExecutor創建的線程你是更能了解線程池運行的規則,避免資源耗盡的風險。
七個核心參數:
-
corePoolSize:核心線程數,線程池維護的最少線程數。
-
maximumPoolSize:最大線程數,線程池維護的最大線程數。
-
keepAliveTime:線程空閑時間,當線程池中的線程數大于核心線程數時,這些多余的線程會被銷毀,這個參數定義了這些線程的空閑時間。
-
TimeUnit:時間單位,keepAliveTime的時間單位。
-
workQueue:任務隊列,當提交的任務數量大于線程池當前可用的線程數時,任務會被存放在這個隊列中。
-
threadFactory:線程工廠,用于創建線程池中的線程。
-
handler:拒絕策略,當任務隊列已滿且線程池中的線程數量已達到最大值時,新提交的任務如何被拒絕執行。常用的拒絕策略有AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy和DiscardPolicy。
任務提交流程:
- 首先會判斷運行線程數是否小于coreFoolSize,如果小于,則直接創建新的線程執行任務。
- 如果大于corePoolSize,判斷workQueue阻塞隊列是否已滿,如果還沒滿,則將任務放到阻塞隊列中。
- 如果workQueue阻塞隊列已經滿了則判斷當前線程數是否大于maximumPoolSize,如果沒大于則創建新的線程執行任務。
- 如果大于maximumPoolSize,則執行任務拒絕策略 (具體就是你自己實現的handler)。
這里有個點需要注意下,就是workQueue阻塞隊列滿了,但當前線程數小于maximumPoolSize,這時候會創建新的線程執行任務。
不過一般我們都是將corePoolSize和maximumPoolSize設置相同數量。
keepAliveTime指的就是,當前運行的線程數大于核心線程數了,只要空閑時間達到了,就會對線程進行回收。
四、線程池指定線程數
線程池指定線程數這塊,首先要考量自己的業務是什么樣的??
是cpu密集型的還是io密集型的,假設運行應用的機器CPU核心數是N。
cpu密集型的可以先給到N+1,io密集型的可以給到2N 。
上面這個只是一個常見的經驗做法,具體究竟開多少線程,需要壓測才能比較準確地定下來。
注:線程不是說越大越好,在之前的我也提到過,多線程是為了充分利用CPU的資源。如果設置的線程過多,線程大量有上下文切換,這一部分也會帶來系統的開銷,這就得不償失了。