我有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);
}
}
);
}
但是它不是线程安全的。我如何在这里实现?也许有更优雅的解决方法?
答案 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中使用列表的副本-它应该可以工作。
正如我们在文档中所读到的:
如果存在指定键的值,则尝试计算给定键及其当前映射值的新映射。 整个方法调用都是原子执行的。在计算进行过程中,可能会阻止其他线程对此映射进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。