我有一些使用 ConcurrentHashMap
的代码并想确认我所做的一切是否正确。
映射将字符串存储为键,将集合 ( Set
) 作为值。我最初有一个实现,我将使用锁 strip 模式以原子方式执行一些操作(放置、删除等),但后来意识到我可以使用 computeIfAbsent/putIfAbsent
来代替它。 (对于看跌期权)和 computeIfAbsent
(用于删除)。多个线程调用所有 4 个方法(get、put、removeKey、removeValue)。
谁能告诉我我的 AFTER 代码是否正确且线程安全?提前致谢!
private final ConcurrentMap<K, Set<V>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<K, Object> locks = new ConcurrentHashMap<>();
public Set<V> getValue(K key) {
if (map.get(key) == null) return null;
return map.get(key).stream().map(k -> k.getValue()).collect(Collectors.toSet());
}
之前
private void putValue(K key, V value) {
Object lock = locks.putIfAbsent(key, new Object());
if (lock == null) lock = locks.get(key);
Set<V> existingSet = map.computeIfAbsent(key, k -> {
Set<V> values = new ConcurrentSkipListSet<>(MY_COMPARATOR);
values.add(value);
return values;
});
if (existingSet != null) { // <- my guess is that this is unnecessary
synchronized (lock) {
map.get(key).add(expiringValue);
}
}
}
public void removeKey(K key) {
if (key == null) return;
if (map.get(key) != null) {
Object lock = locks.get(key);
synchronized (lock) {
map.remove(key);
}
locks.remove(key);
}
}
public void removeValue(K key, V value) {
if (key == null || value == null) return;
if (map.get(key) != null) {
Object lock = locks.get(key);
synchronized (lock) {
map.get(key).remove(value);
if (map.get(key).size() == 0) {
map.remove(key);
}
}
}
}
之后
private void putValue(K key, V value) {
map.computeIfAbsent(key, k -> new ConcurrentSkipListSet<>(MY_COMPARATOR)).add(value);
}
public void removeKey(K key) {
map.remove(key);
}
public void removeValue(K key, V value) {
Set<ExpiringValue<V>> resultingValues = map.computeIfPresent(key, (k, values) -> {
values.remove(value);
return values;
});
if (resultingValues != null && resultingValues.size() == 0) {
map.remove(key);
}
}
最佳答案
至少一个可能的问题是您可能会丢失 putValue
的值。 computeIfAbsent 是线程安全的,但 add() 不再是线程安全的。因此,您可以(取决于您的逻辑)提出以下场景:
T1: computeIfAbsent creates the set for key K
T2: removes K
T1: performs add on the set, which is no longer in the map
关于java - ConcurrentHashMap:将集合存储为值时需要同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44854553/