線程池的好處
- 降低頻繁創建、銷毀線程的開銷
- 便於統一管理線程(數量等)
- 提高響應時間
Java中的線程池
- Executors:創建線程池的工廠類。
- Executors.newFixedThreadPool(nThreads):創建固定大小的線程池。
- Executors.newCachedThreadPool():無限線程池。
- Executors.newSingleThreadExecutor():創建單個線程的線程池。
- Executors.newScheduledThreadPool():創建跑定時任務的線程池。
這4個線程池底層都是調用的new ThreadPoolExcutor(),這個構造方法有很多參數,下面一一分析
- coolPoolSize:核心線程數
- maxPoolSize:最大線程數
- waitTime:線程空閑等待時間
- timeUnit:時間單位
- 阻塞隊列
- 拒絕策略:有4種
- 直接拋異常
- 直接丟棄任務
- 將隊列中最老的任務丟掉並將新任務入隊
- 直接用當前線程執行該任務
- 線程工廠
這些參數和線程池的執行流程有關,線程池的執行流程:
- 當任務提交到線程池時,假如當前線程數小於核心線程數,直接創建線程執行,並且不會銷毀,直到達到核心線程數。
- 當核心線程都在執行還有任務提交時,任務放在阻塞隊列中。
- 阻塞隊列也滿了以后,繼續創建線程執行任務,直到達到最大線程數。
- 最大線程也滿了以后,執行對應的拒絕策略。
- 當線程空閑下來以后,線程在達到線程空閑等待時間后銷毀,直至數量降低至核心線程數。
addWorker():1、增加工作線程數(cas增加一個標記位)2、創建工作線程。
Worker是一個Runnable對象,還繼承了AQS,重寫了獲取state和釋放state的方法,沒有實現重入特性。1、lock表示正在執行任務,不應該被中斷,也不應該被其他的線程重入;2、shutdown的時候會去加鎖,只有無鎖的時候才可以終止,不可重入導致shutdown不能解鎖,必須等工作結束再終止。
執行任務時會加鎖,為了在shutdown時不終止正在進行的任務。
最大線程結束的原因是while(getTask()!=null)有超時時間,返回null則跳出循環結束。
Future/Callable
實現原理:FutureTask:run()方法result字段保存返回值,保存好了以后會喚醒阻塞的線程,get()方法拿不到結果時會阻塞,內部使用awaitNode在鏈表中阻塞。
Fork/join
分治思想,拆分任務fork然后join歸並,底層實現了一種叫工作竊取的算法來提高效率。
