Sun在Java5中,對Java線程的類庫做了大量的擴充,其中線程池就是Java5的新特征之一,除了線程池之外,還有很多多線程相關的内容,為多線程的程式設計帶來了極大便利。為了編寫高效穩定可靠的多線程程式,線程部分的新增内容顯得尤為重要。
有關Java5線程新特征的内容全部在java.util.concurrent下面,裡面包含數目衆多的接口和類,熟悉這部分API特征是一項艱難的學習過程。目前有關這方面的資料和書籍都少之又少,大部分介紹線程方面書籍還停留在java5之前的知識層面上。
在Java5之前,要實作一個線程池是相當有難度的,現在Java5為我們做好了一切,我們隻需要按照提供的API來使用,即可享受線程池帶來的極大便利。
線程池的基本思想還是一種對象池的思想,開辟一塊記憶體空間,裡面存放了衆多(未死亡)的線程,池中線程執行排程由池管理器來處理。當有線程任務時,從池中取一個,執行完成後線程對象歸池,這樣可以避免反複建立線程對象所帶來的性能開銷,節省了系統的資源。
Java5提供5種類型的線程池,分别如下:
一:newCachedThreadPool-可變尺寸的線程池(緩存線程池)
(1)緩存型池子,先檢視池中有沒有以前建立的線程,如果有,就reuse(重用),如果沒有,就建立一個新的線程加入池中;
(2)緩存型池子,通常用于執行一些生存周期很短的異步型任務;是以一些面向連接配接的daemon型server中用得不多;
(3)能reuse(重用)的線程,必須是timeout IDLE内的池中線程,預設timeout是60s,超過這個IDLE時長,線程執行個體将被終止及移出池;
(4)注意,放入CachedThreadPool的線程不必擔心其結束,超過TIMEOUT不活動,其會自動被終止。
二:newFixedThreadPool-固定大小的線程池
(1)newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能随時建新的線程;
(2)其獨特之處:任意時間點,最多隻能有固定數目的活動線程存在,此時如果有新的線程要建立,隻能放在另外的隊列中等待,直到目前的線程中某個線程終止直接被移出池子;
(3)和cacheThreadPool不同,FixedThreadPool沒有IDLE機制(可能也有,但既然文檔沒提,肯定非常長,類似依賴上層的TCP或UDP IDLE機制之類的),是以FixedThreadPool多數針對一些很穩定很固定的正規并發線程,多用于伺服器;
(4)從方法的源代碼看,cache池和fixed池調用的是同一個底層池,隻不過參數不同:
fixed池線程數固定,并且是0秒IDLE(無IDLE);
cache池線程數支援0-Integer.MAX_VALUE(顯然完全沒考慮主機的資源承受能力),60秒IDLE。
三:ScheduledThreadPool-排程線程池
(1)排程型線程池;
(2)這個池子裡的線程可以按schedule依次delay執行,或周期執行。
四:SingleThreadExecutor-單例線程池
(1)單例線程,任意時間池中隻能有一個線程;
(2)用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE)。
五、自定義線程池--ThreadPoolExecutor
參數:
corePoolSize
核心線程數,核心線程會一直存活,即使沒有任務需要處理。當線程數小于核心線程數時,即使現有的線程空閑,線程池也會優先建立新線程來處理任務,而不是直接交給現有的線程處理。
核心線程在allowCoreThreadTimeout被設定為true時會逾時退出,預設情況下不會退出。
maximumPoolSize
當線程數大于或等于核心線程,且任務隊列已滿時,線程池會建立新的線程,直到線程數量達到maxPoolSize。如果線程數已等于maxPoolSize,且任務隊列已滿,則已超出線程池的處理能力,線程池會拒絕處理任務而抛出異常。
keepAliveTime
當線程空閑時間達到keepAliveTime,該線程會退出,直到線程數量等于corePoolSize。如果allowCoreThreadTimeout設定為true,則所有線程均會退出直到線程數量為0。
unit
keepAliveTime 參數的時間機關。
workQueue
執行前用于保持任務的隊列。此隊列僅保持由 execute 方法送出的 Runnable 任務。
抛出:
IllegalArgumentException - 如果corePoolSize或keepAliveTime小于零,或者maximumPoolSize小于或等于零,或者corePoolSize 大于maximumPoolSize。
NullPointerException - 如果workQueue為null
eg、
//建立等待隊列
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(20);
//建立一個單線程執行程式,它可安排在給定延遲後運作指令或者定期地執行。
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 2, TimeUnit.MILLISECONDS, queue);
//建立實作了Runnable接口對象,Thread對象當然也實作了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
//将線程放入池中進行執行
pool.execute(t1);
pool.execute(t2);
//關閉線程池
pool.shutdown();