線程池在Java併發編程中,有着舉足輕重的位置,學習和掌握它是學習Java的重中之重。反正有空看看,學點知識,又不虧。編程
在開發中,合理使用線程池能帶來什麼好處呢?數組
線程池內部持有一個用於存儲工做任務的隊列,在覈心線程滿了時候,會將任務存儲到隊列中。經常使用隊列類型:bash
ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
複製代碼
在線程的構造方法中,共有5個參數:併發
Executors.defaultThreadFactory();
得到默認的線程工廠。主要做用就是給線程起個名字而已。//execute()方法執行任務
executor.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
//submit()方法提交任務
executor.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
複製代碼
提交到線程池中有種方式:execute()方法和submit()方法。ide
execute()方法提交的任務沒法得到返回值,沒法判斷提交狀態。 submit()方法能夠得到返回Future類型的對象,根據Future對象能夠判斷任務是否執行成功和經過get()方法得到返回值,但get()方法會阻塞當前線程一段時間。學習
SHUTDOWN
狀態。而後中斷全部沒有正在執行任務的線程。STOP
狀態。嘗試中止全部正在執行或者暫停任務的線程,並返回等待執行任務的列表。因爲二者都是遍歷線程池中的工做線程,而後中斷線程,因此沒法響應中斷的線程可能永遠沒法終止。ui
當咱們提交一個新任務到線程池時,任務在線程池的流程是怎樣的呢?spa
任務隊列的任務何時被處理?線程
線程池中線程處理任務有兩種方式:一種就是新建線程處理任務,另外一種就是循環從阻塞隊列獲取任務來執行。code
有時咱們僅僅是使用一下線程池,不會本身定製線程池,畢竟線程池的構造方法參數那麼多,個人媽耶。那看看類Executors提供的四個線程池。
//建立FixedThreadPool線程池
Executors.newFixedThreadPool(nThreads);
//newFixedThreadPool方法的實現
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
複製代碼
建立一個FixedThreadPool線程池,線程的核心線程coreThreadSize和線程池線程容量maximumPoolSize都爲nThreads。因爲使用的無界的LinkedBlockingQueue隊列,將致使maximumPoolSize參數失效,隊列對任務未來者不拒。這裏將保活時間設爲0,意味着空線程會被當即終止。
//建立CachedThreadPool線程池
Executors.newCachedThreadPool();
//newCachedThreadPool方法的實現
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
複製代碼
CachedThreadPool的核心線程爲0,線程池容量爲Integer.MAX_VALUE,意味着maximumPoolSize是無界的。保活時間keepAliveTime設爲60秒,空閒線程閒置60秒後被終止。因爲使用了沒有容量的SynchronousQueue隊列,意味當提交一個新任務到線程池中,沒有空閒線程來對接,就會新建新的線程來處理新任務。
//建立SingleThreadExecutor線程池
Executors.newSingleThreadExecutor();
//SingleThreadExecutor方法的實現
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
複製代碼
能夠看到SingleThreadExecutor能夠看作定製化的FixedThreadPool,將nThreads置爲1,將核心線程和線程池容量設爲1,以保證只有一個線程在執行。
//建立ScheduledThreadPool線程池
Executors.newScheduledThreadPool(corePoolSize);
//newScheduledThreadPool方法的實現
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor方法的實現
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
複製代碼
newScheduledThreadPool方法最終會調用ThreadPoolExecutor的構造來建立線程池。將定製化DelayQueue後的DelayedWorkQueue做爲工做隊列。DelayedWorkQueue隊列會把執行時間小的任務排在前面優先執行。若是執行時間相同,就會優先執行提交時間早的任務。
在經過submit()
方法提交任務到線程池,會返回有結果的Future類型的對象。Future是一個接口,FutureTask繼承它,因此FutureTask也能夠做爲submit()
方法得返回值。同時,FutureTask繼承Runnable接口,這樣又能夠做爲任務提交到線程池中,由調用線程直接執行。
當調用FutureTask的get()
方法,若是FutureTask處於已完成狀態(執行完畢),則會致使調用線程當即放回或者拋出異常。不然會使調用線程阻塞。
當調用FutureTask的cancel()
方法,若是FutureTask處於未啓動狀態(爲執行run方法),則該任務不會被執行;若是處於啓動狀態,會嘗試以中斷來嘗試中止任務。若是已經完成狀態,則返回false。
經過對線程池知識點理解,能夠清晰掌握建立線程池騷姿式和內涵。覺得實戰提供必要的理論知識。
本文是我的學習總結和知識備忘,如知識有誤或片面,請多加指正,謝謝
知識來源《Java併發編程的藝術》& 互聯網 & 《Java併發編程實戰》