我有 HashMap:
private final ConcurrentHashMap<String, List<Client>> clients;
和类(class):
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);
}
}
);
}
但它不是线程安全的。我怎样才能在这里实现它?也许有更优雅的方法来解决它?
最佳答案
我认为你可以使用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 中使用列表的副本 - 它应该可以工作。
正如我们在文档中所读到的:
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.
关于java - 并发 HashMap 删除复杂值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58533987/