線程池的基本原理:
無論是之前在JavaSE基礎中,我們學習過的常量池,還是在操作數據庫時,我們學習過數據庫連接池,以及接下來要學習的線程池,均是一種池化思想,其目的就是為了提高資源的利用率,線程池顧名思義就是對線程對象的一種優化
,如果不使用線程池,那么我們對線程的操作即為手動創建線程對象
,執行任務
,任務執行完畢
,釋放線程對象
,映射到我們生活為我們每次打電話都需要買一個手機,每次打完電話就將手機扔掉,那么這樣一來,無疑是非常的鋪張浪費,而線程池就類似于將手機重復利用而不是每次都換新的,它能很好地提高資源的利用率
,并且由于線程對象是提前創建好的,因此也能夠提高程序的響應速度
。
下面我使用日常生活中最常見的一個例子來說明線程池的原理
我們可以將海底撈作為一個線程池,那么海底撈中的桌子可以看作是線程對象,假設當前店中已經有3張空閑的桌子可以使用,此時來了4組可以需要吃飯,那么服務員會根據先后順序先安排前3組客人進行就餐,剩下的一組客人需要進入等待區,隨后來的客人都會進入等待區,但是等待區的位置也不是無窮無盡的啊,假設我們的等待區只能最多讓2個用戶進行等待,當前如果又來了一個客人,那么就會出現他們既沒有空閑的餐桌供他們使用,等待區也沒有空閑的位置,那么此時由于客人并發量太大了,海底撈的老板就會觸發一種應急方案,就是在當前餐廳空曠的區域加桌子,那么等待區中的第一位客人就可以從等待區中出來了呀,剛剛沒有辦法處理的客人此時就可以加入等待區中,加桌子是挺好的,但是也不能無限加啊,因為餐廳可使用的地方是有限的,當達到最大值后,又來了一位客人,那么服務員只好拒絕接待該客人!
使用Java簡單模擬實現線程池:
package org.example;import java.util.concurrent.*;public class Main {public static void main(String[] args) {//3-->表示核心的線程對象數量,也就是上述海底撈例子中沒加桌子前的餐廳桌子數量//5-->表示最大線程對象的數量,也就是上述海底撈例子中該餐廳最多可容納的桌子數量//1和后面的TimeUnit.SECONDS表示1秒鐘沒有任務,就可以停止工作了//ArrayBlockingQueue-->表示一個等待隊列//defaultThreadFactory-->調用默認的工廠//AbortPolicy拒絕策略//ExecutorService是Java提供的線程池ExecutorService executorService=new ThreadPoolExecutor(3,5,1L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());for (int i=0;i<9;i++){executorService.execute(()->{System.out.println(Thread.currentThread().getName()+"辦理業務");});}executorService.shutdown();}
}
輸出如下所示:
當前線程池最多可容納線程的數量為8,那么到第九個線程就會觸發拒絕策略
pool-1-thread-1辦理業務
pool-1-thread-5辦理業務
pool-1-thread-4辦理業務
pool-1-thread-3辦理業務
pool-1-thread-2辦理業務
pool-1-thread-4辦理業務
pool-1-thread-1辦理業務
pool-1-thread-5辦理業務
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.example.Main$$Lambda$1/1283928880@682a0b20 rejected from java.util.concurrent.ThreadPoolExecutor@3d075dc0[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)at org.example.Main.main(Main.java:15)