java - 并发哈希图删除复杂值
问题描述
我有哈希图:
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 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);
}
}
);
}
但它不是线程安全的。我怎样才能在这里实现它?也许有更优雅的方法来解决它?
解决方案
我认为您可以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 中使用列表的副本 - 它应该可以工作。
正如我们在文档中看到的:
如果指定键的值存在,则尝试在给定键及其当前映射值的情况下计算新映射。整个方法调用以原子方式执行。在计算过程中,其他线程对该映射的某些尝试更新操作可能会被阻塞,因此计算应该简短而简单,并且不得尝试更新该映射的任何其他映射。
推荐阅读
- python - 压缩列表中的多个 lambda 函数未执行
- osgi - 是否有一种简单的方法来列出接口的消费者组件?
- c++ - 如何用修改后的十六进制 ASCII 符号替换 ByteArray 元素?
- python - 如何使用 Ajax 和 CherryPy 运行 python 脚本以从 Web 界面通过 SSH 连接到 Raspberry Pi Zero
- azure - 打开逻辑应用程序时:发生未知错误(代码 502)
- java - 如何使用 cucumber 和 selenium web 驱动程序为 web 应用程序双语(英语和阿拉伯语)执行相同的测试步骤
- selenium - 我们可以在 XPATH 中将 Condition 与轴一起使用吗?
- angular - 如何在等待从Angular中的服务获取数据的可观察对象时显示加载微调器
- docker - Docker Go 模板提取图像短名称
- spring-boot - 用于 gRpc 服务的 API 网关