池化技術應用:線程池、數據庫連接池、http連接池等等。
池化技術的思想主要是為了減少每次獲取資源的消耗,提高對資源的利用率。
線程池提供了一種限制、管理資源的策略。 每個線程池還維護一些基本統計信息,例如已完成任務的數量。
使用線程池的好處:
-
降低資源消耗:通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。
-
提高響應速度:當任務到達時,可以不需要等待線程創建就能立即執行。
-
提高線程的可管理性:線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,監控和調優。
二 Executor框架
Executor框架不僅包括了線程池的管理,還提供了線程工廠、隊列以及拒絕策略等,讓並發編程變得更加簡單。
Executor框架的使用示意圖
-
主線程首先要創建實現Runnable或Callable接口的任務對象。
-
把創建完成的實現Runnable/Callable接口的對象直接交給ExecutorService執行:
ExecutorService.execute(Runnable command)或者ExecutorService.sumbit(Runnable command)或ExecutorService.sumbit(Callable <T> task).
-
如果執行ExecutorService.submit(...),ExecutorService將返回一個實現Future接口的對象。最后,主線程可以執行FutureTask.get()方法來等待任務執行完成。主線程也可以執行FutureTask.cancel()來取消次任務的執行。
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorDemo { private static final int CORE_POOL_SIZE = 5; private static final int MAX_POOL_SIZE = 10; private static final int QUEUE_CAPACITY = 100; private static final Long KEEP_ALIVE_TIME = 1L; public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<>(QUEUE_CAPACITY), new ThreadPoolExecutor.CallerRunsPolicy()); //執行線程代碼 executor.shutdown(); } }
CORE_POOL_SIZE:核心線程數定義了最小可以同時運行的線程數量。
MAX_POOL_SIZE:當隊列中存放的任務到達隊列容量的時候,當前可以同時運行的線程數量變為最大線程數。
QUEUE_CAPACITY:當新任務加入是會先判斷當前運行的線程數量是否達到核心線程數,如果達到的話,任務就會被存放到隊列中。
KEEP_ALIVE_TIME:當線程池中的線程數量大於核心線程數時,如果這時沒有新的任務提交,核心線程外的線程不會立即銷毀,而是會等待,直到等待的時間超過KEEP_ALIVE_TIME才會被回收銷毀。
ThreadPoolExecutor.CallerRunsPolicy():調用執行自己的線程運行任務,也就是直接在調用execute方法的線程運行(run)被拒絕的任務,如果執行程序已關閉,則會丟棄任務。因此這種策略會降低新任務的提交速度,影響程序的整體性能。另外,這個策略喜歡增加隊列容量。如果應用程序可以承受此延遲並且不能任務丟棄一個任務請求的話,可以選擇這個策略。
線程池分析原理
有一個簡單且使用面比較廣的公式:
-
CPU密集型任務(N+1):這種任務消耗的主要是CPU資源,可以將線程數設置為N(CPU核心數)+1,比CPU核心數多出來一個線程是為了防止線程偶發的缺頁中斷,或者其他原因導致的任務暫停而帶來的影響。一旦任務停止,CPU就會出於空閑狀態,而這種情況下多出來一個線程就可以充分利用CPU的空閑時間。
-
I/O密集型(2N):