爲什麼要用線程池:
- 線程在java中是一個對象,更是操作系統的資源,線程的創建銷燬需要時間。如果創建+銷燬時間>執行任務時間就很不划算。
- java對象佔用堆內存,操作系統線程佔用系統內存,根據jvm規範,一個線程默認最大棧大小爲1M,這個棧空間是需要系統內存中分配的。因此線程過多,會消耗很多內存。
- 操作系統需要頻繁切換線程上下文,影響性能。
通過使用線程池可以控制線程數量,並且實現線程的重複利用。
線程池概念(組件)
- 線程池管理器:用於創建並管理線程池,包括創建線程,銷燬線程,添加新任務
- 工作線程:線程池中的執行任務的線程,在沒有任務時處於等待狀態,可以循環的執行任務
- 任務接口:每個任務必須實現的接口,以供工作線程調度任務的運行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等
- 任務隊列:用於存放沒有被處理的任務,提供一種緩衝機制。
線程池接口定義和實現類
- 接口 Executor 最上層的接口,定義了執行任務的方法execute(Runnable))
- 接口 ExecutorService 繼承了Executor接口,拓展了Callable、Future、關閉等相關方法
- 接口 ScheduledExecutorService 繼承了ExecutorService,增加了定時任務相關方法
- 實現類 ThreadPoolExecutor 基礎、標準的線程池實現
- 實現類 ScheduledTreadPoolExecutor 繼承了ThreadPoolExecutor,實現了ScheduledExecutorService中定時任務相關方法
標準線程池
參數:
- corePoolSize(int):核心線程數
- maximumPoolSize(int):最大線程數
- keepAliveTime(long):超出核心線程數的線程等待存活時間
- unit(TimeUnit):keepAliveTime時間單位
- workQueue(BlockingQueue<Runnable>):任務隊列
- threadFactury(ThreadFactory):線程創建工廠
- handler(RejectedExecutionHandler):拒絕策略
任務執行流程:
- 是否達到核心線程數量?如果沒有達到,創建一個工作線程來執行任務
- 工作隊列是否已滿?如果沒滿,則將新提交的任務存儲在工作隊列裏
- 是否達到線程池最大數量?如果沒達到,則創建一個新的工作線程來執行任務
- 執行自定義或默認的拋出RejectedExecutionException拒絕策略來處理任務
定時任務線程池
參數:
- corePoolSize(int) 核心線程數
- threadFactory(ThreadFactory) 線程創建工廠
- handler(RejectedExecutionHandler) 拒絕策略
最大線程數爲Integer.MAX_VALUE,存活時間爲0,使用DelayWorkQueue延時隊列作爲延時任務存放隊列。
定時任務使用方式:
scheduleAtFixedRate、scheduleWithFixedDelay
線程池的關閉
shutdown:線程池被關閉後,如果提交新任務,則會直接執行拒絕策略,但是會等待已有任務全部執行完成
shutdownNow:線程池被關閉後,無法提交新任務,並且會嘗試中斷有所正在執行的任務,返回等待的任務列表
控制線程數量
一般使CPU使用率達到80%
計算行任務:cpu數量的1-2倍
I/O型任務:可以使用更多的線程,根據具體的I/O阻塞時長決定