線程安全性——《Java併發編程實戰》學習筆記一

一、線程安全性

    線程安全代碼的核心:管理對共享的(Shared)和可變的(Mutable)狀態的訪問操作。  “共享”:變量可以由多個線程同時訪問; “可變”:變量的值在生命週期內可以發生變化。即:一個對象是共享和且可變得,同時由多個線程訪問訪問時,可能出現線程安全的問題。

    什麼樣的代碼纔是線程安全性的?

    當多個線程訪問某個類時,它始終能表現出正確的行爲,那麼就稱這個類是線程安全的。其核心就是正確性。正確性指某個類的行爲與其規範一致,在良好的規範中通常會定義各種不變性條件來約束對象的狀態,以及定義各種後驗條件來描述對象操作的結果。

二、原子性

    競態條件:當某個計算的正確性取決於多個線程的交替執行時序時,那麼就會發生競態條件。

    1、先檢查後執行:基於一種可能失效的觀察結果來做出判斷或者執行某個計算。例:單例中的懶漢模式採用DCL;

    2、讀取-修改-寫入:基於對象之前的狀態來定義對象狀態的裝換。例:++count。

    如果將上述競態條件等組合操作以原子方式執行,就能夠保證線程安全性。

三、加鎖機制

    加鎖機制保證了複合操作的原子性。

    Java通過synchronized提供一種內置的鎖機制來支持原子性。每個Java對象都可以用作一個實現同步的內置鎖(Intrinsic Lock)或監視器鎖(Monitor Lock)。線程在進入同步代碼塊或方法(內置鎖獲取的唯一途徑)前會自動獲得鎖,並且在正常或異常退出同步代碼塊時釋放鎖。

    Java的內置鎖相當於一種互斥鎖。當線程A持續佔用鎖後,線程B申請此鎖,會一直阻塞,直到線程A釋放鎖。由於內置鎖的互斥性,在多線程下,內置鎖保護的同步代碼塊會以原子方式執行。

    內置鎖是可重入的,某個線程能夠獲得一個已經由它自身持有的鎖。重入的一種實現方法是,爲每個鎖關聯一個獲取計數值和一個所有者線程。內置鎖若是非重入的,容易在連續訪問多個加鎖方法時死鎖。

四、活躍性與性能

    內置鎖爲每個共享的和可變的狀態變量添加同步,會造成這些代碼路徑完全是串行,那麼代碼的執行性能將非常低。

    因此,通過縮小代碼塊的作用範圍,將不影響共享狀態且執行時間較長的操作從同步塊中分離出去,保證併發性和線程安全性。當執行時間較長的計算或者可能無法快速完成的操作時(例,網絡I/O或控制檯I/O),一定不要持有鎖,會嚴重影響代碼的活躍性和併發性。

 

《Java併發編程實戰》學習筆記一

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