简体   繁体   English

Java CHM同步

[英]Java CHM synchronisation

Following up on this question ( Java thread safety - multiple atomic operations? ), I don't want to add more questions to it, but now I have this doubt: 跟进这个问题( Java线程安全-多个原子操作? )之后,我不想对其添加更多问题,但是现在我有一个疑问:

private final Map<String, Set<String>> data = Maps.newConcurrentMap();

... then in a method ...

if (data.containsKey("A")) {
    data.get("A").add("B");
}

It should be something like this: 应该是这样的:

synchronized(data) {
    if (data.containsKey("A")) {
        data.get("A").add("B");
    }
}

In order to be thread-safe. 为了是线程安全的。 Is that correct? 那是对的吗?

So operations are atomic, but combining them would require synchronisation, is that right? 因此,操作是原子的,但是将它们组合起来将需要同步,对吗? At that point, would it make sense to just use a simple HashMap instead of a concurrent one, as we're manually handling sync? 到那时,在我们手动处理同步时,仅使用简单的HashMap而不是并发的HashMap是否有意义?

Is there any method in CHM to make this work atomically? CHM中是否有任何方法可以使这项工作原子化?

In your specific case, you might want to use computeIfPresent method of ConcurrentHashMap : 在您的特定情况下,您可能要使用ConcurrentHashMap computeIfPresent方法

data.computeIfPresent("A", (k, v) -> { v.add("B"); return v; } );

From the javadocs: 从javadocs:

If the value for the specified key is present, attempts to compute a new mapping given the key and its current mapped value. 如果存在指定键的值,请尝试在给定键及其当前映射值的情况下计算新映射。 The entire method invocation is performed atomically . 整个方法调用是原子执行的

So there's no need for explicit synchronization. 因此,无需显式同步。

synchronised(data) {
    if (data.containsKey("A")) {
        data.get("A").add("B");
    }
}

You probably need to show more code. 您可能需要显示更多代码。

Looking only at this, the only possible issue is that someone removes the Set found at "A" after your if check. 仅查看此内容,唯一可能的问题是, if检查,则有人会删除在"A"处找到的Set。 If you don't ever remove map entries you need no synchronization at all. 如果您从未删除映射条目,则根本不需要同步。

If you do remove map entries concurrently, you could use computeIfPresent to arrive at the updated map. 如果确实要同时删除映射条目,则可以使用computeIfPresent来获取更新的映射。

You could also do 你也可以

Set<String> set = data.get("A");
if (set != null) set.add("B");

Since you are not actually producting a new Set, I find this more idiomatic than computeIfPresent (which should compute a new value). 由于您实际上并没有生产新的Set,因此我发现它比computeIfPresent (应该计算一个新值)更惯用。

Note that you need to make all these Sets thread-safe as well. 请注意,您还需要使所有这些Set成为线程安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM