1. 程式人生 > >5、java.util.concurrent 執行緒類

5、java.util.concurrent 執行緒類

7.1Executor框架

為了更好的控制多執行緒,JDK提供了一套執行緒框架Executor,幫助開發人員有效地進行執行緒控制。它們都在java.util.concurrent包中,是JDK併發包的核心。其中有一個比較重要的類:Executors,他扮演著執行緒工廠的角色,我們通過Executors可以建立特定功能的執行緒池。

Executors建立執行緒池方法:

newFixedThreadPooI()方法,該方法返回一個固定數量的執行緒池,該方法的執行緒數始終不變,當有一個任務提交時·若執行緒池中仝閒,則立即執行,若沒有,則會被暫緩在一個任務佇列中等待有空閒的執行緒去執行。

newSingIeThreadExecutor()

方法,建立一個執行緒的執行緒池,若空閒則執行,若沒有空閒執行緒則暫緩在任務列隊中。

newCachedThreadPooI()方法,返回一個可根據實際情況調整執行緒個數的執行緒池,不限制最大執行緒數量,若用空閒的執行緒則執行任務,若無任務則不建立執行緒。並且每一個空閒執行緒會在秒後自動回收。

newScheduledThreadPool()方法,該方法返回一個SchededExecutorService物件,但該執行緒池可以指定執行緒的數量。

7.2 自定義執行緒池

Executors工廠類無法滿足我們的需求,可以自己去建立自定義的執行緒池,其實Executors工廠類裡面的建立執行緒方法其內部實現均是用了TreadPooIExecutor

這個類,這個類可以自定義執行緒。構造方法如下:

public ThreadPoolExecutor(int corePoolSize,

int maximumPooISize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandIer handler) {…}

這個構造方法對於佇列是什麼型別的比較關鍵:

在使用有界佇列時,若有新的任務需要執行,如果執行緒池實際執行緒數小於corePoolSize,則優先建立執行緒,若大於corePoolSize

,則會將任務加入佇列,若佇列己滿,則在匯流排程數不大於maximumPoolSize的前提下,建立新的執行緒,若執行緒數大於maximumPoolSize,則執行拒絕策略。或其他自定義方式。

無界的任務佇列時LinkedBlockingQueue。與有界佇列相比,除非系統資源耗盡,否則無界的任務佇列不存在任務入隊失敗的情況。當有新任務到來,系統的執行緒數小於corePoolSize時,則新建執行緒執行任務。當達到corePoolSize後,就不會繼續增加。若後續仍有新的任務加入,而沒有空閒的執行緒資源,則任務直接進入佇列等待,若任務建立和處理的速度差異很大,那麼無界佇列會保持快速增長,直到耗盡系統記憶體。

JDK拒絕策略:

AbortPoIicy:直接丟擲異常組織系統正常工作

CallerRunsPolicy:只要執行緒池未關閉,該策略直接在呼叫者執行緒中,運行當前被丟棄的任務。

DiscardOIdestPoIicy:丟棄最老的一個請求,嘗試再次提交當前任務。

DiscardPoIicy:丟棄無法處理的任務,不給予任何處理。

如果需要自定義拒絕策略可以實現RejectedExecutionHandIer介面。(推薦)

8.1 Concurrent.util常用類

CyclicBarrier使用:

假設有這樣一個場景:每個執行緒代表一個跑步運動員,當運動員都準備好後,才一起出發,只要有一個人沒有準備好,大家都等待。

CountDownLacth使用:

他經常用於監聽某些初始化操作,等初始化執行完畢後,通知主執行緒繼續工作。

Callable 和 Future使用:

這個例子其實就是我們之前實現的Future模式。jdk給予我們一個實現的封裝,使用非常簡單。

Fure模式非常話合在處理耗時很長的業務輯時進行使用,可以有效的減小系統的響應時間,提高系統的吞吐量。

=============================================================================

Semaphore訊號量非常適合高併發訪問,新系統在上線之前,要對系統的訪問量進行評估,當然這個值肯定不是隨便拍拍腦袋就能想出來的,是經過往的經驗、資料、歷年的訪問量,己經推廣力度講行一個合理的評f佔,當然評估標準不能太大也不能太小,太大的話投入的資源達不到實際效果,純粹浪費資源,太小的話,某個時間點一個高峰值的訪問量上來直接可以壓垮系統。

相關概念.

PV(page view)網站的總訪問量,頁面瀏覽量或點選量,使用者每重新整理一次就會被記錄一次。

UV(unique Visitor)訪問網站的一臺電腦客戶端為一個訪客。一般來講,時間上以00:00 -24:00 之內相同ip的客戶端只記錄一次·

QPS(query per second)即每秒查詢數,qps很大程度上代表了系統業務上的繁忙程度,每次請求的背後,可能對應著多次磁碟I/O,多次網路請求,多個cpu時間片等。我們通過qps可以非常直觀的瞭解當前系統的業務情況,一旦當前qps超過所設定的預警閥值,可以考慮增加機器對叢集擴容,以免壓力過大導致宕機,可根據前期的壓力測試得到估值,在結合後期綜合運維的情況,估算出閥值。

RT(resnsetime)即請求的響應時間,這個指標非常關鍵,直接說明前端使用者的體驗,因此任何系統設計師都想降低rt時間。

當然還涉及cpu、記憶體、網路、磁碟等情況,更細節的問題很多,如select、update、delete/ps 等資料庫層面的統計。

容量評估:一般來說通過開發、運維、測試、以及業務等相關人員,綜合出系統的一糸列

閥值,然後我們根據關鍵閥值如qps、rt等,對系統講行有效的變更。

一般來講,我們講行多輪壓力測試以後,可以對系統進行峰值評估,採用所謂的80/20原則,即80%的訪問請求將在20%的時間內達到。這樣我們可以根踞系統對應的PV計算出峰值qps

峰值qps=(總PV×80%)/(60×60×24×20%)

然後再將總的峰值QPS 除以單臺機器所能承受的最高的qps值,就是所要機器的數量:機器數=總的峰值qps/壓測得出的單機極限qps

當然不排除系統在上線前進行大型促銷活動,或者雙十一、雙十二熱點事件、遭受到DDos攻擊等情況,系統的開發和運維人員急要了解當前系統執行的狀態和負載情況,一般都會有後臺系統去維護·

Semaphore可以控制系統的流量:

拿到訊號量的執行緒可以進入,否則就等待。通過acquire()和release()獲取和釋放訪問許可。