java並發編程實踐學習(2)--對象的組合


  1. 先驗條件(Precondition):某些方法包含基於狀態的先驗條件。例如,不能從空隊列中移除一個元素,在刪除元素前隊列必須處於非空狀態。基於狀態的先驗條件的操作成為依賴狀態操作。
  2. 在單線程中,如果某操作無法滿足先驗條件,就只能失敗,但在並發程序中先驗條件可能會由於其他線程執行的操作而變成真。
  3. java中等待某個條件為真的各種內置機制(包括等待和通知機制)都與內置加鎖緊密關聯。
  4. 所有權和封裝性總是相關聯的:對象封裝它擁有的所有權,對象對它的封裝的狀態擁有所有權。
  5. 發布了某個可變對象的引用,那就不再擁有獨占的控制權。
  6. 容器類通常表現出一種“所有權分離”的形式。

4.1設計線程安全的類

在設計線程安全類的過程中,需要包含以下三個基本要素:

  • 找出構成對象狀態的所有變量
  • 找出約束狀態變量的不可變性條件
  • 建立對象狀態的並發訪問管理策略

 4.3委托給線程安全的類

可以將共享資源委托給一個線程安全的類。比如ConcurrentHashMap,copyOnWriteArrayList.

如果一個類時由多個獨立且線程安全的狀態變量組成,並且在所有的操作中都不包含無效狀態轉換,那么可以將線程安全性委托給底層狀態變量。

下面是一個監控車輛位置的實例。其中Point是線程安全不可變的類。

/**
* 不可變
*/
@Immutable
class Point{
public final int x,y;

Point(int x,int y ) {
this.x = x;
this.y = y;
}
}

/**
* 委托給線程安全類的車輛追蹤器
*/
@ThreadSafe
class DelegatingVehicleTracker{
private final ConcurrentHashMap<String,Point> locations;
private final Map<String,Point> unmodifiableMap;

public DelegatingVehicleTracker(Map<String,Point> points) {
this.locations = new ConcurrentHashMap<>(points);
this.unmodifiableMap = Collections.unmodifiableMap(locations);
}

public Map<String,Point> getLocations(){
return unmodifiableMap;
}

public Point getLocation(String id){
return locations.get(id);
}

public void setLocation(String id,int x,int y){
if(locations.replace(id,new Point(x,y)) == null){
throw new IllegalArgumentException("invalid vehicle name:"+id);
}
}
}

  如果一個狀態變量是線程安全的,並且沒有任何不變性條件來約束它的值,在變量的操作上也不存在任何不允許的狀態轉換,那么就可以安全地發布這個變量。

同樣是車輛追蹤,我想要獲取位置,還可以修改位置,安全性問題可以交給底層SafePoint:

/**
* 線程安全且可變的Point類
*/
@ThreadSafe
class SafePoint{
@GuardedBy("this") private int x,y;
private SafePoint(int[] a){
this(a[0],a[1]);
}
public SafePoint(SafePoint p){
this(p.get());
}
public SafePoint(int x,int y){
this.x = x;
this.y = y;
}
public synchronized int[] get(){
return new int[] {x,y};
}
public synchronized void set(int x,int y){
this.x =x;
this.y = y;
}
}

/**
* 安全發布底層狀態的車輛追蹤器
*/
@ThreadSafe
class PublishingVehicleTracker{
private final Map<String,SafePoint> locations;
private final Map<String,SafePoint> unmodifiableMap;

PublishingVehicleTracker(Map<String, SafePoint> locations, Map<String, SafePoint> unmodifiableMap) {
this.locations = locations;
this.unmodifiableMap = unmodifiableMap;
}

public Map<String,SafePoint> getLocations(){
return unmodifiableMap;
}
public SafePoint getLocation(String id){
return locations.get(id);
}
public void setLocation(String id,int x,int y){
if (!locations.containsKey(id))
throw new IllegalArgumentException("invalid vehicle name:"+id);
locations.get(id).set(x,y);
}
}

  4.5將同步策略文檔化

在文檔中說明客戶代碼需要了解的線程安全性保證,以及代碼維護人員需要了解的同步策略。

synchronized,volatile或者任何一個線程安全類都對應於某種同步策略,用於在並發訪問時確保數據的完整性。一定要在忘記之前記錄下來。

可以使用@GuardedBy("this")或者別的來注釋鎖。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com