您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關如何理解Java常見知識點中的線程池,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
線程池的基本思想是一種對象池,在程序啟動時就開辟一塊內存空間,里面存放了眾多(未死亡)的線程,池中線程執行調度由池管理器來處理。當有線程任務時,從池中取一個,執行完成后線程對象歸池,這樣可以避免反復創建線程對象所帶來的性能開銷,節省了系統的資源。
降低資源消耗:通過重復利用已創建的線程降低線程創建和銷毀造成的消耗(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最后死機)。;
提高響應速度:當任務到達時,任務可以不需要等到線程創建就能立即執行;
提高線程的可管理性:線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
對線程進行一些簡單的管理,比如:延時執行、定時循環執行的策略等,運用線程池都能進行很好的實現
一個線程池包括以下四個基本組成部分:
線程池管理器(ThreadPool):用于創建并管理線程池,包括 創建線程池,銷毀線程池,添加新任務;
工作線程(WorkThread):線程池中線程,在沒有任務時處于等待狀態,可以循環的執行任務;
任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完后的收尾工作,任務的執行狀態等;
任務隊列(taskQueue):用于存放沒有處理的任務。提供一種緩沖機制。
講到線程池,要重點介紹java.uitl.concurrent.ThreadPoolExecutor類,ThreadPoolExecutor是線程池中最核心的一個類。
我們可以通過ThreadPoolExecutor來創建一個線程池
new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);
corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會創建一個線程來執行任務,即使其他空閑的基本線程能夠執行新任務也會創建線程,等到需要執行的任務數大于線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前創建并啟動所有基本線程。
maximumPoolSize(線程池最大大小):線程池允許創建的最大線程數。如果隊列滿了,并且已創建的線程數小于最大線程數,則線程池會再創建新的線程執行任務。值得注意的是如果使用了無界的任務隊列這個參數就沒什么效果。
runnableTaskQueue(任務隊列):用于保存等待執行的任務的阻塞隊列。
ThreadFactory:用于設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字,Debug和定位問題時非常又幫助。
RejectedExecutionHandler(拒絕策略):當隊列和線程池都滿了,說明線程池處于飽和狀態,那么必須采取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。n AbortPolicy:直接拋出異常。
keepAliveTime(線程活動保持時間):線程池的工作線程空閑后,保持存活的時間。所以如果任務很多,并且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。
TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
向線程池提交任務
我們可以通過execute()或submit()兩個方法向線程池提交任務,不過它們有所不同
execute()方法沒有返回值,所以無法判斷任務知否被線程池執行成功
threadsPool.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } });
submit()方法返回一個future,那么我們可以通過這個future來判斷任務是否執行成功,通過future的get方法來獲取返回值
try { Object s = future.get(); } catch (InterruptedException e) { // 處理中斷異常 } catch (ExecutionException e) { // 處理無法執行任務異常 } finally { // 關閉線程池 executor.shutdown(); }
線程池的關閉
我們可以通過shutdown()或shutdownNow()方法來關閉線程池,不過它們也有所不同
shutdown的原理是只是將線程池的狀態設置成SHUTDOWN狀態,然后中斷所有沒有正在執行任務的線程。
shutdownNow的原理是遍歷線程池中的工作線程,然后逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止。shutdownNow會首先將線程池的狀態設置成STOP,然后嘗試停止所有的正在執行或暫停任務的線程,并返回等待執行任務的列表。
ThreadPoolExecutor執行的策略
線程數量未達到corePoolSize,則新建一個線程(核心線程)執行任務
線程數量達到了corePools,則將任務移入隊列等待
隊列已滿,新建線程(非核心線程)執行任務
隊列已滿,總線程數又達到了maximumPoolSize,就會由(RejectedExecutionHandler)拋出異常
四種拒絕策略
ThreadPoolExecutor.AbortPolicy() 拋出java.util.concurrent.RejectedExecutionException異常
ThreadPoolExecutor.DiscardPolicy() 拋棄當前的任務
ThreadPoolExecutor.DiscardOldestPolicy() 拋棄舊的任務 (隊列中的第一個任務替換為當前新進來的任務執行)
ThreadPoolExecutor.CallerRunsPolicy() 重試添加當前的任務,他會自動重復調用execute()方法
1. CachedThreadPool():可緩存線程池。
線程數無限制
有空閑線程則復用空閑線程,若無空閑線程則新建線程 一定程序減少頻繁創建/銷毀線程,減少系統開銷
CachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程
2. FixedThreadPool():定長線程池。
可控制線程最大并發數(同時執行的線程數)
超出的線程會在隊列中等待
如果某個線程因為執行異常而結束,那么線程池會補充一個新線程。
3. ScheduledThreadPool():
定時線程池。
支持定時及周期性任務執行。
newscheduledThreadPool創建一個定長線程池,支持定時及周期性任務執行。延遲執行示例代碼如下.表示延遲1秒后每3秒執行一次
public class ThreadPoolExecutorTest3 { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName() + ": delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS);// 表示延遲1秒后每3秒執行一次 } }
4. SingleThreadExecutor():單線程化的線程池。
有且僅有一個工作線程執行任務
所有任務按照指定順序執行,即遵循隊列的入隊出隊規則
newSingleThreadExecutor創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行,如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行
通過繼承線程池并重寫線程池的beforeExecute,afterExecute和terminated方法,我們可以在任務執行前,執行后和線程池關閉前干一些事情。如監控任務的平均執行時間,最大執行時間和最小執行時間等。這幾個方法在線程池里是空方法。
上述就是小編為大家分享的如何理解Java常見知識點中的線程池了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。