深挖java线程池
目錄
一、線程池
1.簡單介紹
2.幾種線程池
3.實際使用哪個線程池
二、線程池的七大參數
三、線程池底層工作原理
四、拒絕策略
1.什么是拒絕策略
2.都有哪幾種jdk默認的拒絕策略。
五、手寫線程池代碼
六、配置線程池
1.CPU密集型
一、線程池
1.簡單介紹
線程池的優勢:
? ? 線程池做的工作主要是控制運行的線程的數量,處理過程中將任務放入隊列,然后在線程創建后啟動這些任務,如果線程數量超過了最大數量,超出數量的線程排隊等候,等其它線程執行完畢,再從隊列中取出任務來執行。
? ? 他的主要特點為:線程復用;控制最大并發數;管理線程。
? ? 第一:降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。
? ? 第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
? ? 第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
? ? Java中的線程池是通過Executor框架實現的,該框架用到了Executor,Executors,ExecutorService,ThreadPoolExecutor這幾個類。
2.幾種線程池
Executors.newScheduledThreadPool() :帶有定時任務的線程池
java8新出的Executors.newWorkStealingPool(int) :java8新增,使用目前機器上可用的處理器作為它的并行級別。
Executors.newFixedThreadPool(int) :執行長期的任務,性能好很多。
Executors.newSingleThreadExecutor() :一個任務一個任務執行的場景。
Executors.newCachedThreadPool() :適用:執行很多短期異步的小程序或者負載較輕的服務器。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class MyThreadPoolDemo {public static void main(String[] args) {// 一池5個處理線程ExecutorService executorService = Executors.newFixedThreadPool(5);ExecutorService executorService2 = Executors.newCachedThreadPool();ExecutorService executorService3 = Executors.newSingleThreadExecutor();try {// execute無返回值,submit有返回值executorService.execute(() ->{System.out.println("execute");});// 可傳Runnable// executorService.submit(); // 有返回值的} catch (Exception e){e.printStackTrace();} finally {executorService.shutdown();}} }3.實際使用哪個線程池
? ? 一個默認的都不用,生產上只能使用自定義的!以下是阿里巴巴java開發手冊中的內容:
二、線程池的七大參數
七大參數——最終的構造方法:
1.corePoolSize:線程池中的常駐核心線程數。
? ? 在創建了線程池后,當有請求任務來之后,就會安排池中的線程去執行任務,近似理解為今日當值線程。
? ? 當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中。
2.maximumPoolSize:線程池能夠容納同時執行的最大線程數,此值必須大于等于1。
3.keepAliveTime:多余的空閑線程的存活時間。
? ? 當前線程池線程數量超過corePoolSize時,當空閑時間達到keepAliveTime值時,多余空閑線程會被銷毀直到只剩下corePoolSize個線程為止。
4.unit:keepAliveTime的單位。
5.workQueue:任務隊列,被提交但尚未被執行的任務。
6.threadFactory:表示生成線程池中工作線程的線程工廠,用于創建線程,一般用默認的即可。
7.handler:拒絕策略,表示當隊列滿了并且工作線程大于等于線程池的最大線程數(maximumPoolSize)時如何來拒絕。
三、線程池底層工作原理
四、拒絕策略
1.什么是拒絕策略
? ? 等待隊列也已經滿了,再也塞不下新任務了,同時,線程池中的max線程也達到了,無法繼續為新任務服務。
? ? 這時候我們就需要拒絕策略機制合理的處理這個問題。
2.都有哪幾種jdk默認的拒絕策略。
? ? AbortPolicy(默認):直接拋出RejectedExecutionException異常阻止系統正常運行。
? ? CallerRunsPolicy:“調用者運行”一種調節機制,該策略既不會拋棄任務,也不會拋出異常,而是將某些任務回退到調用者,從而降低新任務流量。
? ? DiscardOldestPolicy:拋棄隊列中等待最久的任務,然后把當前任務加入隊列中嘗試再次提交當前任務。
? ? DiscardPolicy:直接丟棄任務,不做任何處理也不拋出異常。如果允許任務丟失,這是最好的一種方案。
五、手寫線程池代碼
注意點:
①.如果隊列滿了,再添加線程時,會開啟新線程,隊列中的線程還是等待,后來進來的線程會先執行。
import java.util.concurrent.*;public class MyThreadPoolWriteMySelf {public static void main(String[] args) {ExecutorService executor = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try{// 設置啟動的線程數,觀察線程池執行任務的變化。for (int i = 0; i < 9; i++) {final int a = i;executor.execute(() ->{System.out.println("開始處理" + a + Thread.currentThread().getName());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}});}} catch (Exception e){e.printStackTrace();} finally {executor.shutdown();}} }六、配置線程池
1.CPU密集型
// 獲取CPU核心數
System.out.println(Runtime.getRuntime().availableProcessors());
?? ?CPU密集的意思是該任務需要大量的運算,而沒有阻塞,CPU一直全速運行。
? ? CPU密集任務只有在真正的多核CPU上才可能得到加速(通過多線程)。
? ? 而在單核CPU上,無論你開幾個模擬的多線程該任務都不可能得到加速,因為CPU總的運算能力就那些
? ? CPU密集型任務配置盡可能少的線程數量:一般公式:CPU核數+1個線程的線程池。
2.IO密集型(分兩種情況)
①由于IO密集型任務線程并不是一直在執行任務,則應配置盡可能多的線程,如CPU核數*2。
②IO密集型,即該任務需要大量的IO,即大量的阻塞。
? ? 在單線程上運行IO密集型的任務會導致浪費大量的CPU運算能力浪費在等待。
? ? 所以在IO密集型任務中使用多線程可以大大的加速程序運行,即使在單核CPU上,這種加速主要就是利用了被浪費掉的阻塞時間。
? ? IO密集型時,大部分線程都阻塞,故需要多配制線程數:
? ? 參考公式:CPU核數/1-阻塞系數(阻塞系數在0.8~0.9之間)
? ? 比如8核CPU:8/1-0.9=80個線程數。
總結
- 上一篇: ArrayList不是并发安全的?那么在
- 下一篇: java死锁以及解决方案