并发哈希图删除复杂值

时间:2019-10-24 04:07:03

标签: java multithreading dictionary thread-safety

我有HashMap:

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

和班级:

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

我从多个线程中调用线程安全方法“ removeElement ”,该方法必须从列表中删除一个值。

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

但是,当然不行。当我得到Method抛出'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);
                }
            }
    );
}

但是它不是线程安全的。我如何在这里实现?也许有更优雅的解决方法?

1 个答案:

答案 0 :(得分:1)

我认为您可以在这种情况下使用ConcurrentHashMap::computeIfPresent,前提是不为相同的键放置相同的module Foo def func; puts "YO"; end end class Bar class << self include Foo end func end 实例:

List

由于CompletableFuture.runAsync(() -> { clients.computeIfPresent(client.getName(), (name, clients1) -> { List<Client> currentClients = new ArrayList<>(clients1); currentClients.remove(client); return currentClients.isEmpty() ? null : currentClients; }); }); 是原子执行的,并且我们正在remappingFunction中使用列表的副本-它应该可以工作。

正如我们在文档中所读到的:

  

如果存在指定键的值,则尝试计算给定键及其当前映射值的新映射。 整个方法调用都是原子执行的。在计算进行过程中,可能会阻止其他线程对此映射进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。