Java線程池執行邏輯

問題:線程是不是越多越號

1、線程在Java中是一個對象,也是操作系統的重要資源,線程的創建、銷燬需要時間,如果創建時間+銷燬時間>執行任務的時間那就很不合算了

2、Java對象佔用堆內存,操作系統線程佔用系統內存年,根據JVM規範,一個線程默認最大棧大小1M,這個棧空間是需要從系統內存中分配的,
線程過多,會消耗很多的內存

3、操作系統需要頻繁的切換上下文,影響性能

所以,線程並不是越多越好,爲了方便的控制線程的數量,這才引進了線程池

線程池執行邏輯

1、首先判斷你是否達到核心線程數
    
    1.1 如果沒有達到,創建一個新的線程執行任務

2、如果已經達到核心線程數,進而判斷工作隊列是否已滿
    
    2.1 如果沒滿,那將新的任務放入工作隊列中

3、如果工作隊列已滿,再判斷是否已經達到最大線程數

    3.1 如果沒有達到,創建一個新的線程執行任務

4、如果已經達到了最大線程數,再執行拒絕策略


隊列共有三種
    1.直接切換。一個工作隊列的一個很好的默認選擇是一個SynchronousQueue ,將任務交給線程,無需另外控制。 在這裏,如果沒有線程可以立即運行,那麼嘗試排隊任務會失敗,因此將構建一個新的線程。 處理可能具有內部依賴關係的請求集時,此策略可避免鎖定。 直接切換通常需要無限制的maximumPoolSizes,以避免拒絕新提交的任務。 這反過來允許無限線程增長的可能性,當命令繼續以平均速度比他們可以處理的速度更快地到達時。 
    2.無界隊列。 使用無界隊列(例如LinkedBlockingQueue沒有預定容量)會導致新的任務,在隊列中等待,當所有corePoolSize線程都很忙。 因此,不會再創建corePoolSize線程。 (因此,最大值大小的值沒有任何影響。)每個任務完全獨立於其他任務時,這可能是適當的,因此任務不會影響其他執行; 例如,在網頁服務器中。 雖然這種排隊風格可以有助於平滑瞬態突發的請求,但是當命令繼續達到的平均速度比可以處理的速度更快時,它承認無界工作隊列增長的可能性。 
    3.有邊界的隊列。 有限隊列(例如, ArrayBlockingQueue )有助於在使用有限maxPoolSizes時防止資源耗盡,但可能更難調整和控制。 隊列大小和最大池大小可能彼此交易:使用大隊列和小型池可以最大限度地減少CPU使用率,OS資源和上下文切換開銷,但可能導致人爲的低吞吐量。 如果任務頻繁阻塞(例如,如果它們是I / O綁定),則系統可能能夠安排比您允許的更多線程的時間。 使用小型隊列通常需要較大的池大小,這樣可以使CPU繁忙,但可能會遇到不可接受的調度開銷,這也降低了吞吐量。

拒絕策略可以自定義默認有4中策略可用:
    1.在默認ThreadPoolExecutor.AbortPolicy ,處理程序會引發運行RejectedExecutionException後排斥反應。 
    2.在ThreadPoolExecutor.CallerRunsPolicy中,調用execute本身的線程運行任務。 這提供了一個簡單的反饋控制機制,將降低新任務提交的速度。 
    3.在ThreadPoolExecutor.DiscardPolicy中 ,簡單地刪除無法執行的任務。 
    4.在ThreadPoolExecutor.DiscardOldestPolicy中 ,如果執行程序沒有關閉,則工作隊列頭部的任務被刪除,然後重試執行(可能會再次失敗,導致重複)。 
可以定義和使用其他類型的RejectedExecutionHandler類。 這樣做需要特別注意,特別是當策略被設計爲僅在特定容量或排隊策略下工作時。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章