我有哈希映射: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 ”,该方法必须从列表中删除一个值。@Overridepublic 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' 异常时,我解决了这样的问题:@Overridepublic 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 回答
Cats萌萌
TA贡献1805条经验 获得超9个赞
我认为您可以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 中使用列表的副本 - 它应该可以工作。
正如我们在文档中可以读到的:
如果指定键的值存在,则尝试计算给定键及其当前映射值的新映射。整个方法调用都是原子执行的。当计算正在进行时,其他线程对此映射的某些尝试更新操作可能会被阻止,因此计算应该简短且简单,并且不得尝试更新此映射的任何其他映射。
添加回答
举报
0/150
提交
取消