一、設計線程安全的類
在設計線程安全類的過程中,需要包含以下三個基本要素:
. 找出構成對象狀態的所有變量。
. 找出約束狀態變量的不變性條件。
. 建立對象狀態的併發訪問管理策略。
分析對象的狀態,首先從對象的域開始。 變量按作用域劃分:
. 全局變量
. 局部變量
. 方法行參
. 異常處理參數
1. 收集同步需求
如果不瞭解對象的不變性條件與後驗條件,那麼就不能確保線程安全性。要滿足在狀態變量的有效值或狀態轉換上的各種約束條件,就需要藉助原子性和封裝性。
說的更簡略些是Java線程安全都是因爲共享變量,共享變量後會因爲多個線程同時修改導致不正確的問題,所以收集一共有多少處會涉及到這些需要同步的變量,只有收集說有可能出問題的因素基於此之上保證所有元素線程安全也才能保證程序是線程安全的。
2. 依賴狀態的操作
先驗條件是值滿足某個條件之後才能進行處理。例如:首先判斷一個隊列是否爲空,如果爲空。。。,如果不爲空。。。其中判斷隊列是否爲空就是先驗條件。
如果在某個操作中包含有基於狀態的先驗條件,那麼這個操作就稱爲依賴狀態的操作。
? 滿足可見性就可以?
3. 狀態的所有權
單獨一個基本對象比較保證其安全性,但是如果是包含對象的集合(容器類 例如:ArrayList),容器類通常表現出一種“所有權分離”的形式。
即使用線程安全的容器類(Collections.synchronizedList(List<T>)),也只能保證容器相關的操作是線程安全的,如果發佈了可變對象的引用,就不會擁有獨佔的控制權。(非線程安全)
二、實例封裝
將數據封裝在對象內部,可以將數據的訪問限制在對象的方法上,從而更容易確保線程在訪問數據時總能持有正確的鎖。
封閉機制更易於構造線程安全的類,因爲當封閉類的狀態時,在分析類的線程安全性時就無須檢查整個程序。
即使封閉能保證對象內所有處理都是現成安全的,但是還需要注意當對象發佈後還是可能出現問題,例如HashSet<Persion> 除保證Persion是線程安全外,還需要保證使用它的Set集合是線程安全的。
- 例子 對象中僅有一個變量,保證此變量線程安全。在方法上使用synchronized
1. Java監聽器模式
synchronized通過指定對象鎖定
2. 示例:車輛追蹤
- 保證容器類實例、容器類包含元素實例線程安全。
三、線程安全性的委託
. 實例講訴如何保證集合類及其包含類線程安全性
. 在現有的線程安全類中添加功能
繼承自當前集合類,加鎖使添加的方法保證安全性,但是這樣比較脆弱。
組合方式,查看書籍源碼
. 將同步策略文檔化