简体   繁体   English

并发 hash map 删除复数值

[英]Concurrent hash map remove complex values

I have HashMap:我有 HashMap:

private final ConcurrentHashMap<String, List<Client>> clients;

And class:和 class:

public static class Client {
    private String name; // it is also the key of the map
    private String url;
}

From several threads, I call thread-safe method " removeElement " which has to remove one value from the list.从多个线程中,我调用线程安全方法“ removeElement ”,它必须从列表中删除一个值。

@Override
public CompletableFuture<Void> removeClient(Client client) {
    return CompletableFuture.runAsync(() ->
            clients.entrySet().removeIf(v ->
                    v.getValue().removeIf(
                            it -> client.url.equals(it.url))
            )
    );
}

But of course, it does not work.但是,当然,它不起作用。 When I had got Method threw 'java.lang.UnsupportedOperationException' exception I resolved the issue like that:当我得到 Method throw 'java.lang.UnsupportedOperationException' 异常时,我解决了这样的问题:

@Override
public CompletableFuture<Void> removeClient(Client client) {
    return CompletableFuture.runAsync(() -> {
                List<Client> currentClients = new ArrayList<>(clients.get(client.getName()));
                currentClients.remove(client);
                if (currentClients.isEmpty()) {
                    clients.remove(client.getName());
                } else {
                    clients.put(client.getName(), currentClients);
                }
            }
    );
}

But it is not thread-safe.但它不是线程安全的。 How can I achieve it here?我怎样才能在这里实现它? Maybe there are more elegant ways to resolve it?也许有更优雅的方法来解决它?

I think you could use ConcurrentHashMap::computeIfPresent in this case assuming that the same List instances are not put for the same keys:我认为您可以在这种情况下使用ConcurrentHashMap::computeIfPresent ,假设没有为相同的键放置相同的List实例:

CompletableFuture.runAsync(() -> {
    clients.computeIfPresent(client.getName(), (name, clients1) -> {
        List<Client> currentClients = new ArrayList<>(clients1);
        currentClients.remove(client);
        return currentClients.isEmpty() ? null : currentClients;
    });
});

Since computeIfPresent is performed atomically and we are using copy of the list inside remappingFunction - it should work.由于computeIfPresent是原子执行的,并且我们在 remappingFunction 中使用列表的副本 - 它应该可以工作。

As we can read in the docs:正如我们在文档中看到的:

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 .整个方法调用以原子方式执行 Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.其他线程对 map 的一些尝试更新操作可能会在计算过程中被阻止,因此计算应该简短而简单,并且不得尝试更新此 map 的任何其他映射。

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

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