猿问

并发哈希图删除复杂值

我有哈希映射:


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 throws '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);

                }

            }

    );

}

但它不是线程安全的。我怎样才能在这里实现它?也许有更优雅的方法来解决它?


拉风的咖菲猫
浏览 103回答 1
1回答

Cats萌萌

我认为您可以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;    });});由于computeIfPresent是原子执行的,并且我们在 remappingFunction 中使用列表的副本 - 它应该可以工作。正如我们在文档中可以读到的:如果指定键的值存在,则尝试计算给定键及其当前映射值的新映射。整个方法调用都是原子执行的。当计算正在进行时,其他线程对此映射的某些尝试更新操作可能会被阻止,因此计算应该简短且简单,并且不得尝试更新此映射的任何其他映射。
随时随地看视频慕课网APP

相关分类

Java
我要回答