【學習筆記】【Java併發編程實戰】第四章 對象的組合

設計線程安全的類

  • 在設計線程安全類的過程中需要包含以下三個基本要素:
    1. 找出構成對象狀態的所有變量
    2. 找出約束狀態變量的不變性條件
    3. 建立對象狀態的併發訪問管理策略
  • 同步策略規定了如何將不變性、線程封閉與加鎖機制等結合起來以維護線程的安全性,並且還規定了哪些變量由哪些鎖來保護。
  • 如果在一個不變性條件中包含多個變量,那麼在執行任何訪問相關變量的操作時,都必須持有保護這些變量的鎖。

實例封閉

  • 將數據封裝在對象內部,可以將數據的訪問限制在對象的方法上,從而更容易確保線程在訪問數據時總能持有正確的鎖。
  • 實例封閉使得不同的狀態變量可以由不同的鎖來保護。
  • 包裝器工廠方法(Collections.SynchronizedList)通過包裝器將容器類封裝在一個同步的包裝器對象中,而包裝器能夠將接口中的每個方法都實現爲同步方法,並將調用請求轉發到底層的容器對象上。只要包裝器對象擁有對底層容器對象的唯一引用,那麼它就是線程安全的。
  • 監視器模式:遵循Java監視器模式的對象會把對象的所有可變狀態都封裝起來,並由對象自己的內置鎖來保護。對於任何一種鎖對象,只要自始至終都使用該鎖對象,都可以用來保護對象的狀態。

線程安全線的委託

  • 如果一個類是由多個獨立且線程安全的狀態變量組成,並且在所有的操作中都不包含無效狀態轉換,那麼可以將線程安全性委託給底層的狀態變量。
  • CopyOnWriteArrayList是一個線程安全的鏈表,特別適用於管理監聽器列表。
  • 如果一個狀態變量是線程安全的,並且沒有任何不變性條件來約束它的值,在變量的操作上也不存在任何不允許的狀態轉換(不需要對變量的有效值進行判斷),那麼就可以安全地發佈這個變量。

在現有的線程安全類中添加功能

  • 擴展方法比直接將代碼添加到類中更加脆弱。
  • 客戶端加鎖是指對於使用某個對象X的客戶端代碼,使用X本身用於保護其狀態的鎖來保護這段客戶代碼。
  • 組合:使用Java監視器模式封裝現有的list,只要外部類中擁有指向底層list的唯一外部引用,就能確保線程安全線。
public class ImprovedList<T> implements List<T> {
	private final List<T> list;
	
	public ImprovedList(List<T> list) {
		this.list = list;
	}

	public synchronized boolean puIfAbsent(T x) {
		boolean contains = list.contains(x);
		if (!contains)
			list.add(x);
		return !contains;
	}

	public synchronized void clear() {
		list.clear();
	}
}

將同步策略文檔化

  • 在文檔中說明客戶代碼需要了解的線程安全線保證,以及代碼維護人員需要了解的同步策略。
  • 設計階段是編寫設計決策文檔的最佳時間。
  • 如果某個類沒有明確地聲明是線程安全的,那麼就不要假設它是線程安全的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章