閱讀103 返回首頁    go 汽車大全


java中線程池的使用(ThreadPoolExecutor)

一.為什麼使用線程池:

1.降低資源消耗。主要指的是降低創建和銷毀線程時產生的cpu資源消耗,線程池通過持續工作的線程執行不斷分配的新任務,來減少頻繁的線程創建與銷毀。

##2.提高響應速度。同上
##3.提高線程的可管理性。線程是稀缺資源,頻繁的創建銷毀,以及沒有控製的大量創建,都會影響係統的穩定性。使用線程池可以統一分配,調優,監控資源。

二.如何創建線程池:

new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler);

corePoolSize:

線程池的基本大小,即在沒有任務需要執行的時候線程池中運行的線程數量。隻有在工作隊列滿了的情況下才會創建超出這個數量的線程。

相關1:

剛剛創建ThreadPoolExecutor的時候,線程並不會 立即啟動,而是要等到有任務提交時才會啟動。如果預先調用了prestartCoreThread()/prestartAllCoreThreads(),則會事先啟動核心線程。

相關2:

考慮到keepAliveTime()和allowCoreThreadTimeOut()超市參數的影響,沒有任務或者沒有足夠任務執行的時候,線程池中運行線程的數量(線程池的大小)小於等於corePoolSize。

maximumPoolSize:

線程池中允許的最大線程數,線程池中的當前運行線程數不會超過這個值,為了保證係統資源有控製的消耗。

相關1:

由於maximumPoolSize可以在運行中通過setMaximumPoolSize()來設置,所以可以通過largestPoolSize()方法來獲得線程池曾經運行過的最大線程數量,來評估當前maximumPoolSize設置是否合適。

keepAliveTime:

當線程空閑後,保留的時間。用來在任務不繁忙的時候減少運行線程數量。在單任務時間較短,任務請求較頻繁的情況下,可以適當延長保留存活時間來減少係統創建和銷毀線程的開銷。

相關1:

對於核心線程,默認一直保留存活,如果將allowCoreThreadTimeOut設置為true,則核心線程也接受keepAliveTime的約束。

TimeUnit unit:

用來修飾keepAliveTime的時間單位,可以為納秒,毫秒,秒,分,小時,天等TimeUnit中的靜態常量。

BlockingQueue:

線程安全的隊列,用來存放排隊的任務。

相關1:

此BlockingQueue的實現有:
->ArrayBlockingQueue:基於數組結構的有屆阻塞隊列,FIFO
->LinkedBlockingQueue:基於鏈表的阻塞隊列,FIFO。吞吐量大於上者。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列
->SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量高於LinkedBlockingQueue.靜態工廠方法Executors.newCachedThreadPool()使用了這個隊列。
->PriorityBlockingQueue:一個具有優先級的無限阻塞隊列。

ThreadFactory:

用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字。

RejectedExecutionHandler:

當隊列和線程池都滿了之後的飽和策略。默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略:
->AbortPolicy:直接拋出異常
->CallerRunsPolicy:隻用調用者所在的線程來運行任務。
->DiscardOldestPolicy:丟棄隊列裏最近一個任務,並執行當前任務。
->DiscardPolicy:不處理,丟棄掉。
->也可以根據應用場景需要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。

三.如何調用線程池:

1.通過execute(Runnable run)方法來執行任務:

threadsPool.execute(new Runnable(){
@override
public void run(){
//code to run.
}
});
但是execute()方法沒有返回值,無法獲得任務執行的情況信息。

2.通過submit()方法來提交執行任務:

Future future=executor.submit(harReturnValueTask);
try{
Object o=future.get();
}catch(Exeception e){

}finally{
executor.shutdown();
}
submit()方法會返回一個future對象,通過future的get()方法,可以獲得任務執行情況。get()方法會阻塞直到任務執行完畢。也可以使用get(long timeout, TimeUnit unit)來設置最長阻塞時間。

如何關閉線程池:

我們可以通過調用線程池的shutdown或shutdownNow方法來關閉線程池,它們的原理是遍曆線程池中的工作線程,然後逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止。但是它們存在一定的區別,shutdownNow首先將線程池的狀態設置成STOP,然後嚐試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表,而shutdown隻是將線程池的狀態設置成SHUTDOWN狀態,然後中斷所有沒有正在執行任務的線程。
隻要調用了這兩個關閉方法的其中一個,isShutdown方法就會返回true。當所有的任務都已關閉後,才表示線程池關閉成功,這時調用isTerminaed方法會返回true。至於我們應該調用哪一種方法來關閉線程池,應該由提交到線程池的任務特性決定,通常調用shutdown來關閉線程池,如果任務不一定要執行完,則可以調用shutdownNow。

今天困了,先寫到這裏,主要參考文章:
https://blog.csdn.net/scboyhj__/article/details/48805881

最後更新:2017-10-08 23:33:01

  上一篇:go  fn quick start
  下一篇:go  適合入門的8個趣味機器學習項目