參考資料《實戰JAVA高併發程序設計》數據庫
同步(Synchronous)與異步(Asynchronous)安全
同步和異步一般用來形容一次方法的調用。 同步方法調用一旦開始,調用者必須等到方法調用返回後才能繼續後邊的行爲。 異步方法調用更像是一個消息傳遞,一旦開始,方法調用就會當即返回,調用者可要繼續後續操做。
併發(Concurrency)和並行(Parallelism)多線程
均可以表示多個任務一塊兒執行。 併發偏重於多個任務交替執行,而這多個任務可能仍是串行的,例如單核CPU執行多個進程,進程之間交替執行。 並行則是多核cPU同時執行多個程序,這幾個程序不會交替執行他們同時在各自的CPU上同時被執行。
臨界區併發
臨界區用來表示一種公共資源或者說共享數據,能夠被多個線程使用,可是每一次只能有一個線程使用它。 一旦臨界區資源被佔用,其餘線程想要使用這個資源,就必須等待。 例如:多人共用打印機
阻塞(Blocking)和非阻塞(Non-Blocking)app
阻塞和非阻塞一般用來形容多線程間的影響。 好比一個線程佔用了臨界區資源,那麼其餘須要該資源的線程就必須等待,等待就會致使線程掛起,這種狀況就稱爲阻塞。 非阻塞強調沒有一個線程能夠妨礙其餘縣城執行,全部線程都會嘗試不斷向前執行。
死鎖(Deadlock)、飢餓(Starvation)和活鎖(Livelock)異步
死鎖飢餓活鎖都屬於多線程的活躍性問題。 死鎖一般狀況下指兩個或多個線程同時佔用彼此須要的資源,你們都不肯意釋放本身的資源而繼續等待對方釋放資源,致使全部線程都沒法繼續運行下去。 飢餓指某一個或多個線程由於種種緣由沒法得到所須要的資源,致使一直赴法執行,好比優先級過低,高優先級進程不斷搶佔它須要的資源。 活鎖是指線程1可使用資源,但它很禮貌,讓其餘線程先使用資源,線程2也可使用資源,但它很紳士,也讓其餘線程先使用資源。這樣互相禮讓,致使兩個線程都沒法使用資源。
阻塞(Blocking)高併發
線程阻塞後,在當前線程未獲得其餘線程釋放本身所需資源以前,當前線程沒法繼續執行,syncronized和重入鎖都會阻塞線程。
無飢餓(Starvation-Free)優化
若是線程有優先級,調度就會傾向於知足高優先級的進程,對資源的分配就會不公平。 對於非公平的鎖來說,系統容許高優先級的線程插隊,這樣就會致使低優先級線程產生飢餓。 若是不區分優先級,知足先來後到,就不會產生飢餓。
無障礙(Obstruction-Free)線程
無障礙是一種最弱的非阻塞調度。 線程不會由於臨界區的問題致使其餘線程被掛起,你們均可以進入臨界區, 可是你們修改數據時,若是線程檢測到數據被改壞了,爲了確保數據安全,線程會回滾本次操做, 若是沒有數據競爭發生,那麼閒層就順利完成本身的工做,走出臨界區。 當臨界區中存在嚴重的衝突時,全部縣城均可能會不斷回滾本身的操做,而致使沒有一個線程能夠走出臨界區。 CAS是一種可能的無障礙實現。 阻塞能夠至關因而悲觀策略,無障礙至關因而樂觀策略,類比數據庫的悲觀鎖和樂觀鎖。
無鎖(Lock-Free)設計
無鎖的並行都是無障礙的。在無鎖的狀態下,全部的線程都能嘗試對臨界區進行訪問。 可是不一樣的是無鎖的併發保證必然有一個線程可以在有限步內萬層操做離開臨界區(對比無障礙)。 在無鎖的調用中,一個典型的特色是可能會包含一個無窮循環,線程不斷嘗試修改共享變量,若是修改爲功,name退出,不然繼續嘗試。 若是某個線程黴,老是嘗試不成功,則會出現相似飢餓的狀況。 原子類的CompareAndSet就是無鎖的一種。
無等待(Wait-Free)
無鎖只要求一個線程能夠在有限步內完成操做,而無等待則在無鎖的基礎上更進一步。 他要求全部的線程都必須在有限步內完成,這樣就不會引飢餓問題。 若是限制步驟上限,還能夠進一步分解爲有界無等待和線程數無關的無等待幾種,它們之間的區別只是對循環次數的限制不通。 一種典型的無等待結構就是RCU(Read-Copy-Update)。 RCU基本思想是讀能夠不加控制,可是在寫的時候先取副本-->修改副本-->找機會回寫。
加速比定義:加速比 = 優化前系統耗時 / 優化後系統耗時。 開始討論這倆貨以前,咱們先來定義一下,每一個線程有不少個執行步驟,這些步驟包含可並行的和只能串行的。
Amdahl
角度: 只有有限個相同的線程須要執行。 對執行單個線程而言: 串行執行時間a,並行執行時間b,對每一個線程而言串行率 F = a / (a + b). 推導: n表示處理器個數,Tn表示使用n個處理器優化後的耗時,T1表示優化前耗時,爲了便於分析咱們假設有與核心處理器個數相同的n個線程在同時執行,Sn爲加速比。
$$ Tn = na + b\ T1 = n(a + b)\ Sn = T1 / Tn=\frac{n(a + b)}{(na + b)} = \frac{(a + b)}{(a + \frac{b}{n})} \ = \frac{1}{\frac{a}{(a + b)} + \frac{b}{n(a + b)}} = \frac{1}{\frac{a}{(a + b)} + \frac{a + b - a}{n (a + b)}}\ = \frac{1}{\frac{a}{(a + b)} + \frac{1}{n} (1-\frac{a}{a + b})}\ =\frac{1}{F + \frac{1}{n} (1 - F)} $$
oschina不支持LaTex數學公式,這裏貼個圖
根據以上公式,咱們假定每一個線程執行分爲步驟1-5,每一個步驟耗時100個時間單位,其中步驟2,5能夠並行,1,3,4只能串行。
串行比F = 300 / 500 = 0.6, 假設有兩個核心,加速比Sn = 1 / (F + 1/2(1-F)) = 1.25. 當n->∞時,Sn = 1 / F = 1 / 0.6 = 1.67. 因而可知,爲了提升系統速度,僅增長CPU的數量並不必定能起到有效的做用。 根據Amhadl定律,使用多核CPU對系統進行優化,效果取決於俄CPU的數量以及系統中串行化程序的比重,CPU越多,串行比重越小,則優化效果越佳。
Gustafson
角度: 有無限個相同線程須要執行。 對執行和核心數n相同數量的線程而言: 串行時間a, 並行時間爲b, F = a / (a + b). 若是單個CPU執行這個多線程須要時間: T1 = a + nb
$$ Sn = \frac{a+nb}{a+b} = \frac{a}{a+b} + \frac {nb}{a+b} = F + n(\frac{a + b - a}{a + b}) = F + n(1 - F) = n - F(n - 1) $$
oschina不支持LaTex數學公式,這裏貼個圖
能夠看到因爲Gustafson定律與Amdahl定律的切入角度不通,這倆貨的公式大相徑庭,咱們更容易發如今Gustafson定律中,只要不斷的累加處理器,就能得到更快的速度。
是否矛盾?
因爲這兩貨結論不通,會不會是其中有一個結論是錯的呢? 其實不是的,他們只是切入角度不通而已,偏重點不一樣而已。 Amhadl: 總路程只有60km(類比有限的線程須要執行) 假設前30km已經行駛了1個小時,那麼不管速度如何快(類比無限增長CPU個數),平均速度都不可能超過60km/h. Gustafson: 路程無限長(類比有無限個線程須要執行) 假設前30km已經行駛了1個小時,那麼只要我在後面的以更快的速度行駛(類比增長CPU個數),那麼我總有一個時刻可以把平均速度提升到超過60km/h甚至90km/h.
從極端角度來講,假如系統中沒有可被並行化的代碼,即F=1,那麼對於這兩個定律,其加速比都是1. 反之若是全是可並行的代碼,即F=0,那麼對於這兩個定律,其加速比都是n。
原子性
可見性
有序性
Happens-Before