2015-11-04 12 views
5

Trên trang 65 và 66 của Java Concurrency in Practice Brian Goetz liệt kê các mã sau:Làm thế nào để DelegatingVehicleTracker (trang 65 Goetz) trả lại chế độ xem "trực tiếp"?

@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 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); 
} 

// Alternate version of getLocations (Listing 4.8) 
public Map<String, Point> getLocationsAsStatic() { 
    return Collections.unmodifiableMap(
      new HashMap<String, Point>(locations)); 
} 
} 

Về lớp này Goetz viết:

" ... phiên bản Delegating [mã trên] Điều này có nghĩa là nếu luồng A gọi getLocations() và chủ đề B sau đó sửa đổi vị trí của một số các điểm , những thay đổi đó được phản ánh trong bản đồ được trả về chủ đề A . "

Bản đồ unmodifiable của Thread A là "sống" theo nghĩa nào? Tôi không thấy những thay đổi của Thread B thông qua các cuộc gọi tới setLocation() sẽ được phản ánh trong unmodifiableMap của Thread A. Điều này có vẻ như trường hợp chỉ khi Thread A xây dựng một thể hiện mới của DelegatingVehicleTracker. Nhưng đã được Thread A để giữ một tham chiếu đến lớp này, tôi không thấy làm thế nào điều này là có thể.

Goetz tiếp tục nói rằng getLocationsAsStatic() có thể được gọi là "chế độ xem không thay đổi của hạm đội được yêu cầu". Tôi bị bối rối. Dường như đối với tôi chính xác là trường hợp ngược lại, một lệnh gọi hàm getLocationsAsStatic() thực sự sẽ trả lại chế độ xem "trực tiếp" và một cuộc gọi đến getLocations(), là lớp không được xây dựng lại, sẽ trả về chế độ xem tĩnh, không thay đổi của đội xe ô tô.

Tôi thiếu gì trong ví dụ này?

Bất kỳ suy nghĩ hoặc quan điểm nào được đánh giá cao!

Trả lời

3

Tôi nghĩ sự nhầm lẫn của bạn là do sự hiểu lầm của Collections.unmodifiableMap. Biến đổi trực tiếp của bản đồ được trả về bởi Collections.unmodifiableMap không được phép, tuy nhiên, việc thay đổi bản đồ sao lưu là hoàn toàn tốt (miễn là bản đồ sao lưu cho phép đột biến).Ví dụ:

Map<String,String> map = new HashMap<>(); 
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(map); 

map.put("key","value"); 

for (String key : unmodifiableMap.keySet()) { 
    System.out.println(key); // prints key 
} 

Vì vậy, unmodifiableMap trong ví dụ DelegatingVehicleTracker được hỗ trợ bởi một bản đồ có thể thay đổi locations (một thread-safe một). setLocation biến thể locations nguyên tử và do đó thay đổi sẽ hiển thị đối với các chuỗi giữ tham chiếu đến số unmodifiableMap khi biết rằng các chuỗi đó không thể biến đổi unmodifiableMap. Người đọc không có quyền truy cập vào locations do đó, việc tắt tiếng sẽ chỉ được thực hiện qua DelegatingVehicleTracker và do đó tên là delegation.

+0

Cảm ơn Sleiman, và bạn khác cũng; giờ thì tôi đã hiểu. Tôi sẽ đánh vần nó ra cho bản thân mình (sử dụng hy vọng cho người khác): DelegatingVehicleTracker có thể sửa đổi, nhưng các lớp client không thể. Một cuộc gọi đến unmodifiableMap trong mã ví dụ của bạn ở trên sẽ ném một ngoại lệ (tôi đã thử nó ra), nhưng, tất nhiên, chèn vào bản đồ không. UnmodifiableMap giống như một chương trình múa rối nhìn thấy qua một màn hình kính khiến khán giả không can thiệp được. –

+0

@BenWeaver có một thuật ngữ cho phép ẩn dụ bạn vừa mô tả, đó là số –

+0

Cảm ơn, Sleiman! –

1

Bản đồ unmodifiable của Thread A là "sống" theo nghĩa nào? Tôi không thấy như thế nào thay đổi do Thread B qua các cuộc gọi đến setLocation() sẽ được phản ánh trong bài viết của một unmodifiableMap

Điều này là do getLocations() trả về một bản đồ bọc unmodifiable của bản đồ thực tế có thể thay đổi.

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

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

Vì vậy, mọi thay đổi sau này sẽ được tự động phản ánh trong cùng một đối tượng Bản đồ nội bộ.

Goetz tiếp tục nói rằng getLocationsAsStatic() có thể được gọi là một "quan điểm không thay đổi của hạm đội yêu cầu"

Mã này

public Map<String, Point> getLocationsAsStatic() { 
return Collections.unmodifiableMap(
     new HashMap<String, Point>(locations)); 
} 

là tĩnh theo nghĩa là tương lai thay đổi đối với locations không được phản ánh vì nó trả về bản đồ mới với bản sao của tất cả các cặp khóa-giá trị hiện tại.

0

getLocations() sẽ trả về một read-only bản đồ đó sẽ phản ánh cập nhật saugetLocations() được gọi. Mặt khác,

getLocationsAsStatic() sẽ trả lại chỉ đọc-chụp nhanh (còn gọi là bản sao sâu) của bản đồ Vị trí tại thời điểm getLocationsAsStatic() được gọi.

Để minh họa:

Map<String, Point> locs  = // a map with point A(1,1) in it 
DelegatingVehicleTracker tracker = DelegatingVehicleTracker(locs); 

Map<String, Point> snapshot = getLocationsAsStatic(); 
Map<String, Point> live  = getLocations(); 

Point newB = // a point A(2,2) 
tracker.setLocation(newB); 

snapshot.get("A"); // will read A(1,1) 
live.get("A");  // will read A(2,2) 
+0

thats thực sự là câu hỏi, đó là những gì OP không hiểu –

Các vấn đề liên quan