关于书籍示例的问题 - Java 并发实践,清单 4.12

mik*_*ike 4 java synchronization immutability

我正在实践 Java 并发中的一个示例,但不明白为什么在以下代码中需要并发安全容器。

我没有看到容器“locations”的状态在构建后如何修改;因此,由于它是通过“不可修改的Map”包装器发布的,因此在我看来,普通的 HashMap 就足够了。

EG,它是并发访问的,但是map的状态只有读者访问,没有作者访问。映射中的值字段通过委托给“SafePoint”类来同步,因此虽然点是可变的,但映射中的哈希键及其关联值(对 SafePoint 实例的引用)永远不会改变。

我认为我的困惑是基于问题中集合的确切状态。

谢谢!!-麦克风

清单 4.12,实践中的 Java 并发(此清单可在此处以 .java 形式提供,也可通过 google 以章节形式提供)

/////////////开始代码

@ThreadSafe
public class PublishingVehicleTracker {

private final Map<String, SafePoint> locations;
private final Map<String, SafePoint> unmodifiableMap;

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

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

// 监视受保护的辅助类

@ThreadSafe
public 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;
}
Run Code Online (Sandbox Code Playgroud)

}

///////////结束代码

Enn*_*oji 5

你是对的。我认为这是 JCiP 中的一个错误。如果您想双重确定,我建议您将其发布到(其)邮件列表: http: //gee.cs.oswego.edu/dl/concurrency-interest

正如你所说,地图没有被修改;值的修改不会导致地图上的任何“写入”。

事实上,我的生产代码完全按照您的建议进行,并且我已在上述邮件列表上提出了有关该代码的问题。JCiP 的一位作者告诉我,可以为容器使用只读哈希图。

这是我的代码的简化版本(没有空检查等)(我最终使用了 google-collection 的 ImmutableMap。):

class Sample {
    private final ImmutableMap<Long, AtomicReference<Stuff>> container;

    Sample(){
        this.container = getMap();
    }

    void setStuff(Long id, Stuff stuff){
        AtomicReference<Stuff> holder = container.get(id);
        holder.set(stuff);
    }
}
Run Code Online (Sandbox Code Playgroud)

它在极端负载下可以长时间完美工作。