-
(1) 從頭開始構(gòu)建一個類, 或?qū)⒍鄠€非線程安全的類組合為一個類時, Java監(jiān)視器模式很有效(見"2_實例封閉.md");
多個線程安全的類組合為一個類時, 可以考慮委托方式
(2) 示例
1° 基于監(jiān)視器模式的車輛追蹤
MonitorVehicleTracker.java
@ThreadSafe public class MonitorVehicleTracker { @GuardedBy("this") private final Map<String, MutablePoint> locations; public MonitorVehicleTracker(Map<String, MutablePoint> locations) { this.locations = deepCopy(locations); } public synchronized Map<String, MutablePoint> getLocations() { return deepCopy(locations); } public synchronized MutablePoint getLocation(String id) { MutablePoint loc = locations.get(id); return loc == null ? null : new MutablePoint(loc); } public synchronized void setLocation(String id, int x, int y) { MutablePoint loc = locations.get(id); if (loc == null) { throw new IllegalArgumentException("No such ID: " + id); } loc.x = x; loc.y = y; } private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) { Map<String, MutablePoint> result = new HashMap<String, MutablePoint>(); for (String id : m.keySet()) { result.put(id, new MutablePoint(m.get(id))); } return Collections.unmodifiableMap(result); } }
MutablePoint.java
@NotThreadSafe public class MutablePoint { public int x, y; public MutablePoint() { x = 0; y = 0; } public MutablePoint(MutablePoint p) { this.x = p.x; this.y = p.y; } }
這個示例中, 雖然MutablePoint線程不安全, 但是MonitorVehicleTracker是安全的: 它采用了監(jiān)視器模式, 用this作為鎖, 并且內(nèi)含的Map對象和Mutable對象都未曾發(fā)布
__2° 基于委托的車輛追蹤__
DelegatingVehicleTracker.java
@ThreadSafe
public class DelegatingVehicleTracker {
private final ConcurrentMap<String, Point> locations;
private final Map<String, Point> unmodifiableMap;
public DelegatingVehicleTracker(Map<String, Point> points) {
locations = new ConcurrentHashMap<String, Point>(points);
unmodifiableMap = Collections.unmodifiableMap(locations);
}
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);
}
}
public Map<String, Point> getLocations() {
return unmodifiableMap;
}
// Alternate version of getLocations
public Map<String, Point> getLocationsAsStatic() {
return Collections.unmodifiableMap(new HashMap<String, Point>(locations));
}
}
Point.java
@Immutable
public class Point {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
這種方式將線程安全委托給了ConcurrentMap類型的locations, 由于Point類時不可變的淑玫,所以如果想要實時更新點的位置, 可以調(diào)用getLocations()函數(shù), 這樣更新會立刻顯示; 如果不需要發(fā)生變化的車輛位置, 可以調(diào)用getLocationsAsStatic()函數(shù), 在這里采用了__淺拷貝__的方式(因為Point不可變, 復制Map的結(jié)構(gòu)即可, 不需要復制它的內(nèi)容)
(3) __線程安全性可以委托給多個狀態(tài)變量, 只要它們是彼此獨立的__
示例
public class VisualComponent {
private final List<KeyListener> keyListeners = new CopyOnWriteArrayList<KeyListener>();
private final List<MouseListener> mouseListeners = new CopyOnWriteArrayList<MouseListener>();
public void addKeyListener(KeyListener listener) {
keyListeners.add(listener);
}
public void addMouseListener(MouseListener listener) {
mouseListeners.add(listener);
}
public void removeKeyListener(KeyListener listener) {
keyListeners.remove(listener);
}
public void removeMouseListener(MouseListener listener) {
mouseListeners.remove(listener);
}
}
這個示例中, keyListeners和mouseListeners的類型是CopyOnWriteArrayList, 這是一個線程安全的容器類型, 并且由于它們互相獨立, 所以VisualComponent的線程安全委托給了keyListeners和mouseListeners
(4) __但是, 如果某個類含有復合操作, 那么委托方式就會失效, 此時必須依靠類自己的加鎖機制__(這個類似于如果只有一個狀態(tài)變量時用volatile就行,但是有多個變量僅用volatile就會失效)