這篇文章主要講解了“Java中的線程池有什么用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java中的線程池有什么用”吧!
Java中的線程池
【1】使用線程池的好處:
1)降低資源消耗,通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。 2)提高響應速度,當任務到達時,任務可以不需要等到線程創建就能立即執行。 3)提高線程的可管理性。線程池可以進行統一分配、調優和監控線程。
【2】構造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler); 參數說明: 1)corePoolSize:核心池的大小。 1)在創建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務到來才創建線程去執行任務。 2)默認情況下,在創建了線程池后,線程池中的線程數為0,當有任務來之后,就會創建一個線程去執行任務。 注意:即使其它空閑的線程能夠執行新任務也會去創建線程,當線程池中的線程數目達到corePoolSize后,就會把到達的任務放到緩存隊列當中。 3)調用prestartAllCoreThreads()或prestartCoreThread()方法來預創建線程,即在沒有任務到來之前就創建corePoolSize個線程或者一個線程。 2)workQueue:任務緩存隊列,是一個阻塞隊列,用來存儲等待執行的任務;類型為BlockingQueue<Runnable>,通??梢匀∠旅?種類型: 1)ArrayBlockingQueue:基于數組的先進先出隊列,此隊列創建時必須指定大??; 2)LinkedBlockingQueue:基于鏈表的先進先出隊列,如果創建時沒有指定此隊列大小,則默認為Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQueue。 eg:靜態工廠方法Executors.newFixedThreadPool()就是使用的這個隊列。 3)SynchronousQueue:這個隊列不會保存提交的任務,而是直接新建一個線程來執行新來的任務。 說明:每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處于阻塞狀態,吞吐量通常要高于LinkedBlockingQueue。 eg:靜態工廠方法Executors.newCachedThreadPool使用的就是這個隊列。 4)PriorityBlockingQueue:一個具有優先級的無限阻塞隊列。 說明: 1>一般使用LinkedBlockingQueue和SynchronousQueue 2>建議使用有界隊列,有界隊列能增加系統的穩定性。 eg:如果線程池里的工作線程全部阻塞,任務積壓在線程池里,如果設置成無界隊列,那么這個隊列會越來越大,有可能會撐滿內存,導致整個系統不可用。 3)maximumPoolSize:線程池中允許創建的最大線程數。 1)如果隊列滿了,并且已創建的線程數小于最大線程數,則線程池會再創建新的線程來執行任務。 2)如果使用了無界的任務隊列,則這個參數就不起什么作用了(隊列默認的大小是:Integer.MAX_VALUE,在隊列未滿之前,線程池是不會再去創建新線程了)。 4)RejectedExecutionHandler:任務拒絕策略,當任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize時,如果還有任務到來就會采取任務拒絕策略,通常有以下四種策略: 1)ThreadPoolExecutor.AbortPolicy: 丟棄任務并拋出RejectedExecutionException異常,默認使用該策略。 2)ThreadPoolExecutor.DiscardPolicy: 丟棄任務,但是不拋出異常;會導致被丟棄的任務無法再次被執行 3)ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程);會導致被丟棄的任務無法再次被執行 4)ThreadPoolExecutor.CallerRunsPolicy: 由調用線程處理該任務;主線程直接執行該任務,執行完之后嘗試添加下一個任務到線程池中,可以有效降低向線程池內添加任務的速度 說明:也可以實現RejectedExecutionHandler接口來自定義策略。 5)keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。 默認情況下,只有當線程池中的線程數大于corePoolSize時,keepAliveTime才會起作用。 但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大于corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0; 6)TimeUnit:參數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性: TimeUnit.DAYS; 天 TimeUnit.HOURS; 小時 TimeUnit.MINUTES; 分鐘 TimeUnit.SECONDS; 秒 TimeUnit.MILLISECONDS; 毫秒 TimeUnit.MICROSECONDS; 微妙 TimeUnit.NANOSECONDS; 納秒 7)ThreadFactory:用于設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字。
【3】其它方法:
任務的提交: execute(Runnable command): 提交后沒有返回值,故無法判斷任務是否被線程池執行成功。 submit(): 提交后返回一個Future對象,通過這個future對象可以判斷任務是否執行成功。 通過future的get()方法來獲取返回值,該方法會阻塞當前線程直到任務完成。 get(long timeout, TimeUnit unit)方法:阻塞當前線程一段時間后立即返回,這時候任務可能沒有執行完。 線程池容量的動態調整: setCorePoolSize() 設置核心池的大小 setMaximumPoolSize() 設置線程池最大能創建的線程數 線程池的關閉: 原理:遍歷線程池中的工作線程,然后逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止。 shutdown() 1>將線程池的狀態設置成SHUTDOWN狀態,然后中斷所有沒有正在執行任務的線程。 2>不再接受新的任務,但是不會立即終止線程池,而是要等所有任務緩存隊列中的任務都執行完后才終止。 shutdownNow() 1>首先將線程池的狀態設置成STOP,然后嘗試停止所有的正在執行或暫停任務的線程,并且清空任務緩存隊列,并返回等待執行任務的列表. 說明: 1)只要調用了這兩個關閉方法中的任意一個,isShutdown方法就會返回true。 2)當所有的任務都已關閉后,才表示線程池關閉成功,這時調用isTerminaed方法會返回true。
【4】線程池的狀態:
// RUNNING狀態:線程池正常運行,可以接受新的任務并處理隊列中的任務 private static final int RUNNING = -1 << COUNT_BITS; // SHUTDOWN狀態:不再接受新任務,但是會執行隊列中的任務 private static final int SHUTDOWN = 0 << COUNT_BITS; // STOP狀態:不再接受新任務,不處理隊列中的任務,中斷正在處理的任務 private static final int STOP = 1 << COUNT_BITS; // 過渡狀態:所有的任務都執行完了,線程池已經沒有有效的線程了,此時線程池的狀態為過渡狀態,并且將要調用terminated()方法 private static final int TIDYING = 2 << COUNT_BITS; // 終止狀態:terminated()方法調用完成后的狀態 private static final int TERMINATED = 3 << COUNT_BITS; 1>當線程池剛創建后,線程池處于RUNNING狀態,可以接受新的任務并處理隊列中的任務 2>如果調用了shutdown()方法,則線程池處于SHUTDOWN狀態,此時線程池不能夠接受新的任務,它會等待所有任務執行完畢; 3>如果調用了shutdownNow()方法,則線程池處于STOP狀態,此時線程池不能接受新的任務,并且會去嘗試終止正在執行的任務; 4>當線程池處于SHUTDOWN或STOP狀態,并且所有工作線程已經銷毀,任務緩存隊列已經清空或執行結束后,線程池被設置為TERMINATED狀態。
【5】線程池的處理流程:
ThreadPoolExecutor執行execute方法分下面4種情況。 1)如果當前運行的線程少于corePoolSize,則創建新線程來執行任務(注意,執行這一步驟需要獲取全局鎖)。 2)如果運行的線程等于或多于corePoolSize,則將任務加入BlockingQueue。 3)如果無法將任務加入BlockingQueue(隊列已滿),則創建新的線程來處理任務(注意,執行這一步驟需要獲取全局鎖)。 4)如果創建新線程將使當前運行的線程超出maximumPoolSize,任務將被拒絕,并調用 RejectedExecutionHandler.rejectedExecution()方法。
感謝各位的閱讀,以上就是“Java中的線程池有什么用”的內容了,經過本文的學習后,相信大家對Java中的線程池有什么用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。