在設計線程安全類的過程當中,須要包含如下三個基本要素: 1. 找出構成對象狀態的全部變量 2. 找出約束狀態變量的不變性條件 3. 創建對象狀態的併發訪問管理策略
遵循Java監視器模式的對象會把對象的全部可變狀態都封裝起來,並由對象本身的內置鎖來保護 如下代碼是對象使用私有鎖的例子:安全
public class PrivateLock { private final Object myLock = new Object(); public void doSomething() { synchronized(myLock) {...} } }
委託是建立線程安全類的一個有效手段:只需讓現有的線程安全類管理全部的狀態便可。 經過多個線程安全類組合而成的類,其線程安全性視狀況而定。併發
要在現有的類中添加線程安全操做,有兩種方法:線程
public class BetterVector<E> extends Vector<E> { public synchronized boolean putIfAbsent(E x) { boolean absent = !contains(x); if (absent) {add(x);} return absent; } }
擴展的方法比直接修改源代碼要脆弱,由於同步策略實現被分佈到了多個單獨維護的源代碼文件中。若是底層的類改變了同步策略並選擇了不一樣的鎖來保護它的狀態變量,那麼子類會被破壞。 3. 客戶端加鎖機制 客戶端加鎖機制是指,對於使用某個對象X的客戶端代碼,使用X自己用於保護其狀態的鎖來保護這段客戶代碼。要使用客戶端加鎖機制,必須知道對象X使用的是哪個鎖。以下代碼中,第一個實現版本使用了不一樣的鎖,因此其並非原子的。設計
public class ListHelper<E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); //verson 1 public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } //verson 2 public boolean putIfAbsent(E x) { synchronized(list) {//使用list本身的鎖 boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } } }
在文檔中說明客戶代碼須要瞭解的線程安全性保證,以及代碼維護人員須要瞭解的同步策略code