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

发布于 2024-08-27 22:46:40 字数 1816 浏览 7 评论 0原文

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

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

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

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

谢谢!! -Mike

清单 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);
  }
}

// 监视受保护的辅助类

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

}

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

I am working through an example in Java Concurrency in Practice and am not understanding why a concurrent-safe container is necessary in the following code.

I'm not seeing how the container
"locations" 's state
could be modified after construction; so since it is published through an 'unmodifiableMap' wrapper, it appears to me that an ordinary HashMap would suffice.

EG, it is accessed concurrently, but the state of the map is only accessed by readers, no writers. The value fields in the map are syncronized via delegation to the 'SafePoint' class, so while the points are mutable, the keys for the hash, and their associated values (references to SafePoint instances) in the map never change.

I think my confusion is based on what precisely the state of the collection is in the problem.

Thanks!! -Mike

Listing 4.12, Java Concurrency in Practice,
(this listing available as .java here, and also in chapter form via google)

/////////////begin code

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

// monitor protected helper-class

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

}

///////////end code

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

莫多说 2024-09-03 22:46:40

你是对的。我认为这是 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);
    }
}

它在极端负载下工作了很长一段时间。

You are right. I think it is an error in JCiP. If you want to be double sure, I suggest you post it to (its) mailing list at:
http://gee.cs.oswego.edu/dl/concurrency-interest

Like you said, the map is not modified; modification of the value does not result in any "writes" on the map.

In fact, my production code does exactly what you suggest, and I have asked question on the said mailing list about that code. One of the author of JCiP told me it is okay to use a read-only hashmap for the container.

Here is the simplified version (no null check etc.) of my code (I ended up using google-collection's 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);
    }
}

It has worked perfectly under extreme load, for an extended time.

晨曦÷微暖 2024-09-03 22:46:40

@Zwei,感谢您的建议 - Joe Bowbeer & Tim Peierls(JCiP 合著者)证实,从技术上讲,普通的哈希映射在这种情况下就足够了。 (尽管任何现实世界的设计可能都有额外的要求,需要并发映射)

原因是底层映射是
-从最终字段可传递到达
- 自从通过“getLocations()”发布以来没有改变(实际上它在 ctor 之后从未改变,但这不是必需的)
-正确构建的

Joe 向我指出了几篇非常好的博客文章,更多地解释了 java 不变性的真正含义:

http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html
http://jeremymanson.blogspot.com/2008/ 07/immutability-in-java-part-2.html

我建议读者在那里获得完整的解释。

谢谢!

@Zwei, thanks for the suggestion - Joe Bowbeer & Tim Peierls (JCiP coauthors) confirmed that, technically, an ordinary hash map would suffice in this case. (although any real-world design would probably have extra requirements that would necessitate the concurrent map)

The reasoning is that the underlying map is
-transitively reachable from a final field
-not changed since published via 'getLocations()' (actually its never changed after ctor, but that's not necessary)
-properly constructed

Joe pointed me to a couple very good blog posts explaining more about what java immutability really means:

http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html
http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-2.html

I'd refer readers there for a complete explanation.

Thanks!

七秒鱼° 2024-09-03 22:46:40

setLocation 方法确实修改了地图的内容。

更新:我与一位同事讨论了这个问题,最终我们同意@Zwei Steinen 的结论(给他+1 :-)。

请注意,除了他提到的内容之外,可见性也是一个问题。然而,在这种情况下,地图被声明为final,这保证了这一点。

The method setLocation does indeed modify the contents of the map.

Update: I discussed the issue with a coworker and in the end we came to agree with @Zwei Steinen's conclusion (+1 to him :-).

Note that apart from what he mentioned, visibility is a concern too. However, in this case the map is declared final, which guarantees this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文