您好,登錄后才能下訂單哦!
本篇內容介紹了“Java線程池的原理、使用及性能優化方法是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
線程是操作系統進行時序調度的基本單元。
線程池可以理解為一個存在線程的池子,就是一個容器,這個容器只能存在線程。這個容器有大小,可以放7,8個,也可以放3,4個。也可以把容器裝滿,但是都有一個最大值,比如說12個。比如說我這邊線程池一般都裝5個線程,最多能裝12個。這個時候有五個人需要使用線程池,他就拿走了5個線程,然后在來兩個人怎么辦,他肯定沒有線程可以使用,他必須等著那5個人使用完才行。但是我的池子能裝12個,我只有5個線程怎么行,我肯定還得在在裝幾個線程,要不然人再多一點就不夠了,這時候來了2個,我在生產2個線程,總數到7個,這個時候剩下2個人就不需要等待了,就可以直接使用。如果在來6個人呢,這個時候,我的池子里面可能只剩下5個線程的容量了,我能在生產5個線程但是,還有一個人得在哪等著才行。我也不能讓人家漫無目的的等著啊,我找5個凳子吧,你們坐那等著,然后第一波五個人用完線程結束了,一下子騰出來了5個線程,剩下的一個人可以使用線程,這個時候依次又來了10個人,我的線程只有4個人可以使用,位置能坐五個人,剩下一個人怎么辦,要不直接拒絕,我這邊沒有位,你要不先去別的地方看看,但是直接拒絕肯定很讓人心里不舒服,我得在想幾種拒絕策略。。。,我看我的線程池用的人還比較多,這么多人用,要是有人一直占著我的線程池怎么辦,肯定得想個辦法處理?要不就直接一個線程只能使用1分鐘,使用完之后立刻回收,如果想在使用,重新排隊等待。這樣我的線程生意越做越好,只要有人用,他就一直跑。
是不是有點像飯店或者是自助餐店,自助餐店是比較形象的,我的飯店里面只要有位置就可以坐人,達到最大的量,剩下的客戶只能在門口等待了,飯店里面的客戶走一個,來一個在外邊等待的,如果等待的位置沒有了,客戶看看沒位置了就直接走了,如果有的人特別想吃,就在哪多等一會。在飯店里面的客戶吃的時間也不能太長(一般在沒有位置的情況下),大概2個小時,吃完就要離開。
根據以上我的描述,大概可以確定線程池里面有什么?
裝了多少個線程、能裝多少線程、線程可以保留多長時間、線程等待區、如何拒絕、創建線程
程序的運行必須依靠進程,進程的實際執行單元就是線程。
系統內服務的調用。系統是依托于進程運行的,系統內有很多服務,服務之間有交互,服務的運行依托于線程運行。多服務運行依托于多線程運行。服務之間的調用及數據交換是依托于進程間的內存進行數據交互的,同時線程也可以構建自己的內存空間。依托于進程間的資源調度和數據交互。
多線程可以提高程序的執行性能。例如,有個 90 平方的房子,一個人打掃需要花費 30 分鐘,三個人打掃就只需要 10 分鐘,這三個人就是程序中的“多線程”。
在很多程序中,需要多個線程互相同步或互斥的并行完成工作。
線程相比進程來說,更加的輕量,所以線程的創建和銷毀的代價變得更小。
線程提高了性能,雖然線程宏觀上是并行的,但微觀上卻是串行。從CPU角度線程并無法提升性能,但如果某些線程涉及到等待資源(比如IO,等待輸入)時,多線程允許進程中的其它線程繼續執行而不是整個進程被阻塞,因此提高了CPU的利用率,從這個角度會提升性能。
在多CPU或多核的情況下,使用線程不僅僅在宏觀上并行,在微觀上也是并行的。
多線程可以提高程序的執行性能
比如說吃自助餐,當餐位足夠多的時候,人也足夠多的時候,自助餐盈利也是最多了,同時也可以提供就餐率與客戶滿意度。如果有200個人吃飯,有一百個餐位的話,每個人平均吃1個小時,那200個人吃兩個小時就吃完了。如果只有10個餐位的話,200個人需要吃20個小時左右,想一下如果剩下的在哪里焦急等待吃飯的客戶心里多么的不開心。
自助餐餐的餐位就是線程,當線程足夠多的時候就可以滿足更多的人吃飯,但是也不是說線程越多越好,畢竟不是一定每次都會有200個客戶過來吃飯,就算有200個客戶過來吃飯,也需要評估一下,飯店里面的廚師夠不夠,打掃衛生的阿姨能不能收拾過來,飯店里面的盤子夠不夠等基本的硬件因素。這個就相當于系統的配置一下,需要一些本質上的內存、CPU處理等一些硬件條件。
創建/銷毀線程伴隨著系統開銷,過于頻繁的創建/銷毀線程,會很大程度上影響處理效率(只要線程一直執行就不會銷毀)
記創建線程消耗時間T1,執行任務消耗時間T2,銷毀線程消耗時間T3,如果T1+T3>T2,那么是不是說開啟一個線程來執行這個任務太不劃算了!正好,線程池緩存線程,可用已有的閑置線程來執行新任務,避免了T1+T3帶來的系統開銷,當然一直存活的核心線程也會消耗CPU資源
線程并發數量過多,搶占系統資源從而導致阻塞
我們知道線程能共享系統資源,如果同時執行的線程過多,就有可能導致系統資源不足而產生阻塞的情況,運用線程池能有效的控制線程最大并發數,避免以上的問題
對線程進行一些簡單的管理
比如:延時執行、定時循環執行的策略等運用線程池都能進行很好的實現
提高線程利用率
保證存在業務是的時候使用,不存在業務的時候就釋放掉,合理使用線程,避免資源浪費
提高程序的響應速度
由線程池統一管理的話,資源分配使用統一的調度池進行調度,出現使用線程的情況能避免線程的創建及銷毀的耗時,可以直接使用線程。
便于統一管理線程對象
線程池可以保證線程的統一調配與管理。
可以控制最大并發數
服務器是有線程使用上限的,線程使用對資源也有很大的消耗,所以線程池能很好的控制線程資源,避免浪費。
ThreadPoolExecutor這個類是java中的線程池類,可以使用它進行線程的池化。
// 根據上面的描述大概分析一下線程都需要什么及參數的解析 // corePoolSize 核心線程數,就是上面說的裝了多少個線程 // maximumPoolSize 最大線程數,就是上面說的能裝多少線程 // keepAliveTime 存活時間,就是上面說的線程可以保留多長時間 // TimeUnit 這個是時間單位,有時、分、秒、天等等,是存活時間的單位 // BlockingQueue<Runnable> 這是一個等待隊列,就是上面顯示的線程等待區 // ThreadFactory 線程工廠,就是上面描述的如何創建線程,由誰創建 // RejectedExecutionHandler 拒絕策略,就是上面顯示的如何拒絕,是直接拒絕還是婉拒 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue) public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
可以看到,其需要如下幾個參數:
corePoolSize(必需):核心線程數。默認情況下,核心線程會一直存活,但是當將 allowCoreThreadTimeout 設置為 true 時,核心線程也會超時回收。
maximumPoolSize(必需):線程池所能容納的最大線程數。當活躍線程數達到該數值后,后續的新任務將會阻塞。
keepAliveTime(必需):線程閑置超時時長。如果超過該時長,非核心線程就會被回收。如果將 allowCoreThreadTimeout 設置為 true 時,核心線程也會超時回收。
unit(必需):指定 keepAliveTime 參數的時間單位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
workQueue(必需):任務隊列。通過線程池的 execute() 方法提交的 Runnable 對象將存儲在該參數中。其采用阻塞隊列實現。
threadFactory(可選):線程工廠。用于指定為線程池創建新線程的方式。
handler(可選):拒絕策略。當達到最大線程數時需要執行的飽和策略。
import java.util.concurrent.*; public class ThreadTest { public static void main(String[] args) { ExecutorService threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory()); for (int i = 0; i < 20; i++) { int finalI = i; threadPoolExecutor.submit( ()->{ System.out.println(Thread.currentThread().getName() + "========" + finalI); }); } threadPoolExecutor.shutdown(); } }
執行結果:
pool-1-thread-1========0
pool-1-thread-3========2
pool-1-thread-3========4
pool-1-thread-2========1
pool-1-thread-3========5
pool-1-thread-2========8
pool-1-thread-5========7
pool-1-thread-1========3
pool-1-thread-4========6
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@61e717c2 rejected from java.util.concurrent.ThreadPoolExecutor@66cd51c3[Running, pool size = 5, active threads = 2, queued tasks = 0, completed tasks = 7]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.halo.communication.ThreadTest.main(ThreadTest.java:10)
執行的線程數超過了線程池可容納的大小,線程池使用默認拒絕策略拒絕多余線程執行,然后開始出現異常處理。上面執行的線程數到thread-5,5是線程池的默認最大線程數。然后執行for循環20次,進行執行到8的時候出現異常,說明線程池已經超載滿負荷執行,所以線程池執行拒絕策略。
“Java線程池的原理、使用及性能優化方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。