java有預置線程池:newSingleThreadExecutor,newFixedThreadPool,newCacheedThreadPool,newScheduledThreadPool,newWorkStealingPool。如果不適合,還可以使用ThreadPoolExecutor創建自定義線程池。主要構造方法:
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue) 6 7 public ThreadPoolExecutor(int corePoolSize, 8 int maximumPoolSize, 9 long keepAliveTime, 10 TimeUnit unit, 11 BlockingQueue<Runnable> workQueue, 12 ThreadFactory threadFactory, 13 RejectedExecutionHandler handler)
我們接下來介紹參數,其中線程池大小與前四個參數有關。
- corePoolSize: 核心線程數。
- 剛創建線程池,沒有,即不會預先創建。當任務到來,且當前線程沒有超過corePoolSize,就會創建一個新線程執行該任務,即使其他線程是空閑。
- 不會因為空閑而被釋放,keepAliveTime不適用。
- maximumPoolSize:最大線程數。如上面情況,如果當前線程超過corePoolSize,先嘗試排隊,如果隊列滿了或者其他情況不能入隊,那么它不會排隊,而是檢查線程數是否達到maximumPoolSize,如果沒有,就創建線程,直到線程數達到maximumPoolSize。
- keepAliveTime:空閑線程存活時間。當線程池的線程數大於corePoolSize,額外空閑線程的存活時間。如果到了時間,還沒有新任務,就會釋放線程。值為0,表示線程不會超時釋放。
- unit:
- BlockingQueue:阻塞隊列。可以使用LinkedBlockingQueue(默認無界)、ArrayBlockingQueue、PriorityBlockingQueue(無界)、SynchronousQueue(沒實際存儲空間)。使用無界隊列,需要注意,線程數最多達到corePoolSize,新任務來只能排隊,maximumPoolSize沒意義。SynchronousQueue只有正好有空閑線程,才會入隊成功,否則總是創建新線程,直到達到maximumPoolSize。
- handler:任務拒絕策略。有界隊列,線程數達到maximumPoolSize,隊列滿了,觸發任務拒絕策略。四種處理方式:AbortPolicy(默認,拋出異常),DiscardPolicy(忽略新任務,不拋異常),DiscardOldestPolicy(扔掉等待時間最長,自己排隊),CallerRunsPolicy(任務提交者線程執行任務)
最佳自定義創建線程池,隊列有界,maximumPoolSize有限,使用任務拒絕策略。如果隊列無界,服務不了的任務總是會排隊,消耗內存,甚至引發內存不足異常。如果隊列有界但maximumPoolSize無線,可能會創建過多線程,占內存和CPU。