最近在做項目時,需要用到線程池。
我不喜歡一開始上來就講底層,因爲這樣子很深奧。
對於線程池,java jdk 1.7裏會有對應的接口ExecutorService與實現類newCachedThreadPool /newFixedThreadPool /newScheduledThreadPool 。
這篇博客裏推薦新手先看看,因爲如果只關注怎麼用,先不扔源碼的話,是夠用的。《java ExecutorService》
newCachedThreadPool :可緩存,也就是他會利用已經運行完畢的線程,比如線程池裏有A、B兩個線程,如果現在又來一個請求C。如果線程A現在是空閒的,則可以用線程A來接受請求C,而不用再去new一個線程。
newFixedThreadPool :定長的線程池。也就是池裏的最大線程數是固定的。
- 如果你的線程池容量爲10,線程池裏有A、B兩個線程。如果現在又來一個請求C,他是不會檢查之前的線程進行復用。而是會創建一個新的線程C來接收請求C。
- 如果當前線程池裏已經有10個線程,這時候又來一個新的請求。此時纔會去檢查池裏是否有空閒的線程,如果有的話就利用舊的空閒線程去接收請求。如果沒有的話就放在等待隊列裏。而且直到線程池shutDown(),否則線程池裏的線程是沒有辦法在內存裏釋放的。
- 需要注意的是,newFixedThreadPool的源碼裏的等待隊列使用的是 LinkedBlockingQueue<Runnable>()。當等待隊列是LinkedBlockingQueue的時候,所以該線程池的第二個初始化參數public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue)是無效的。所以如果直接ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3)這樣子建議線程池,則只是確認了第一個參數corePoolSize。第二個參數maximumPoolSize雖然被設置,但是沒有實際效果。如果超過corePoolSize,會全部加到阻塞隊列裏面去。
newScheduledThreadPool :用於定時任務或週期性任務執行。
如果你不想使用上面那些,可以自定義線程池,如下:
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 2, TimeUnit.HOURS, new LinkedBlockingQueue<Runnable>());
參數的含義分別爲:【引用:Java多線程-線程池ThreadPoolExecutor構造方法和規則】
corePoolSize
核心線程數,默認情況下核心線程會一直存活,即使處於閒置狀態也不會受存
keepAliveTime
限制。除非將allowCoreThreadTimeOut
設置爲true
。maximumPoolSize
線程池所能容納的最大線程數。超過這個數的線程將被阻塞。當任務隊列爲沒有設置大小的LinkedBlockingDeque時,這個值無效。
keepAliveTime
非核心線程的閒置超時時間,超過這個時間就會被回收。
unit
指定
keepAliveTime
的單位,如TimeUnit.SECONDS
。當將allowCoreThreadTimeOut
設置爲true
時對corePoolSize生效。workQueue
線程池中的任務隊列.
常用的有三種隊列,
SynchronousQueue
,LinkedBlockingDeque
,ArrayBlockingQueue
。