如何对并发映射的值进行原子操作?
How to make operations on the value of a concurrent map atomic?
假设我在 class 中有以下字段:
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
此 class 的实例在多个线程之间共享。
如果我想在与键关联的集合中添加或删除元素,我可以这样做:
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
setVal.add(new SomeOtherClass());
get
操作是原子操作,因此是线程安全的。但是,不能保证在 get
和 add
指令之间,一些其他线程不会修改结构以扰乱第一个线程的执行。
使整个操作原子化的最佳方法是什么?
这是我想出的,但我认为它不是非常有效(或充分利用 Java 的结构):
我有一个 ReentrantLock 字段,所以我的 class 看起来像这样:
class A {
ReentrantLock lock = new ReentrantLock();
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
}
然后方法调用看起来像这样:
lock.lock();
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
synchronized(setVal) {
lock.unlock();
setVal.add(new SomeOtherClass());
}
我们的想法是,一旦我们确定没有其他人会访问我们正在尝试修改的集合,我们就会解除锁定。但是,我不认为这是对 ConcurrentMap
的最佳利用,或者拥有一个锁、一个并发结构和一个 synchronized
块都用于实现一个操作是很有意义的。
有没有更好的方法来解决这个问题?
ConcurrentHashMap
保证 compute
(或 computeIfAbsent
或 computeIfPresent
)的整个方法调用是原子完成的。所以,例如,你可以这样做:
myMap.compute(someKeyValue, (k, v) -> {v.add(new SomeOtherClass()); return v;});
注:
使用 compute
类似于假设地图中存在 somKeyValue
的原始片段。不过,使用 computeIfPresent
可能更安全。
假设我在 class 中有以下字段:
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
此 class 的实例在多个线程之间共享。
如果我想在与键关联的集合中添加或删除元素,我可以这样做:
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
setVal.add(new SomeOtherClass());
get
操作是原子操作,因此是线程安全的。但是,不能保证在 get
和 add
指令之间,一些其他线程不会修改结构以扰乱第一个线程的执行。
使整个操作原子化的最佳方法是什么?
这是我想出的,但我认为它不是非常有效(或充分利用 Java 的结构):
我有一个 ReentrantLock 字段,所以我的 class 看起来像这样:
class A {
ReentrantLock lock = new ReentrantLock();
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
}
然后方法调用看起来像这样:
lock.lock();
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
synchronized(setVal) {
lock.unlock();
setVal.add(new SomeOtherClass());
}
我们的想法是,一旦我们确定没有其他人会访问我们正在尝试修改的集合,我们就会解除锁定。但是,我不认为这是对 ConcurrentMap
的最佳利用,或者拥有一个锁、一个并发结构和一个 synchronized
块都用于实现一个操作是很有意义的。
有没有更好的方法来解决这个问题?
ConcurrentHashMap
保证 compute
(或 computeIfAbsent
或 computeIfPresent
)的整个方法调用是原子完成的。所以,例如,你可以这样做:
myMap.compute(someKeyValue, (k, v) -> {v.add(new SomeOtherClass()); return v;});
注:
使用 compute
类似于假设地图中存在 somKeyValue
的原始片段。不过,使用 computeIfPresent
可能更安全。