1

这基本上是thisthis或许多其他方面的延续。

我的问题可能很简单,如果我ConcurrentHashMap::compute 在具有一定价值的读者和作者中使用,是否足以确保可见性

我确实知道这种compute方法:

整个方法调用以原子方式执行

这足以保证可见性吗?具体来说,真正的规范/文档是否明智happens-before?为了简化我的问题,这里有一个例子:

static class State {
    private int age;

    int getAge() {
        return age;
    }

    State setAge(int age) {
        this.age = age;
        return this;
    }
} 

和 :

// very simplified, no checks
static class Holder {

    private static final ConcurrentHashMap<String, State> CHM = new ConcurrentHashMap<>();

    public State read(String key) {
        return CHM.compute(key, (x, y) -> y);
    }

    public State write(String key, int age) {
        return CHM.compute(key, (x, y) -> y.setAge(y.getAge() + age));
    }
}

没有人可以访问CHM并且只能通过Holder.

对我来说,答案显然是肯定的,这是安全的,所有读者都会看到最新write方法的结果。我只是无法将这些点与 的文档联系起来ConcurrentHashMap,这很可能是显而易见的,但我似乎想念它。

4

1 回答 1

3

compute()javadoc说明了这个方法的作用:

尝试计算指定键及其当前映射值的映射(或者null如果没有当前映射)。

所以compute() 替换键的值。

用于compute()修改某些对象的内部字段(甚至对象作为值存储在映射中)并不是compute()本意。
因此,自然而然,compute()的规范/文档保证(甚至说)对此一无所知。

关于happens-before,文档中有多次提及:

  • 并发哈希映射

    更正式地说,给定键的更新操作与报告更新值的该键的任何(非空)检索具有发生前的关系。

  • 并发地图

    内存一致性效果:与其他并发集合一样,线程中的操作在将对象ConcurrentMap作为键或值放入之前发生在ConcurrentMap从另一个线程中访问或删除该对象之后的操作之前。

  • java.util.concurrent

    在将对象放入任何并发集合之前线程中的操作发生在另一个线程中从集合中访问或删除该元素之后的操作。

重要的是,该happen-before关系仅在将对象插入/删除/检索到/从集合中得到保证。
在您的情况下,它是同一个State对象(仅在内部更新其字段),因此根据文档ConcurrentHashMap,甚至允许 IMO 决定没有任何更改并跳过剩余的同步步骤。

于 2021-06-04T05:03:25.167 回答