[英]Java - How to make operations on the value of a concurrent map atomic?
Let's say I have the following field inside of a class:假设我在 class 中有以下字段:
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
An instance of this class is shared among many threads.此 class 的一个实例在许多线程之间共享。
If I want to add or remove an element from a set associated with a key, I could do:如果我想从与键关联的集合中添加或删除元素,我可以这样做:
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
setVal.add(new SomeOtherClass());
The get
operation is atomic, therefore thread-safe. get
操作是原子的,因此是线程安全的。 However, there's no guarantee that, in between the get
and the add
instruction, some other thread won't modify the structure messing with the first one's execution.但是,不能保证在
get
和add
指令之间,其他一些线程不会修改结构,干扰第一个执行。
What would be the best way to make the whole operation atomic?使整个操作原子化的最佳方法是什么?
Here's what I've come up with, but I don't believe it to be very efficient (or to be making the best use out of Java's structures):这是我想出的,但我不认为它非常有效(或者无法充分利用 Java 的结构):
I have a ReentrantLock field, so my class looks like this:我有一个 ReentrantLock 字段,所以我的 class 看起来像这样:
class A {
ReentrantLock lock = new ReentrantLock();
ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();
}
Then the method call looks something like this:然后方法调用看起来像这样:
lock.lock();
Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
synchronized(setVal) {
lock.unlock();
setVal.add(new SomeOtherClass());
}
The idea being that we let go of the lock once we have made sure no one else will access the Set we're trying to modify.我们的想法是,一旦我们确定没有其他人将访问我们正在尝试修改的 Set,我们就让 go 锁定。 However, I don't think this is making the best use of the
ConcurrentMap
or that it makes much sense to have a lock, a concurrent structure, and a synchronized
block all used to achieve one operation.但是,我不认为这是对
ConcurrentMap
的最佳利用,或者将锁、并发结构和synchronized
块全部用于实现一个操作是很有意义的。
Is there a best way to go about this?有没有关于 go 的最佳方法?
ConcurrentHashMap
guarantees that the entire method invocation of compute
(or computeIfAbsent
or computeIfPresent
) is done atomically. ConcurrentHashMap
保证compute
(或computeIfAbsent
或computeIfPresent
)的整个方法调用是原子完成的。 So, eg, you could do something like this:因此,例如,您可以执行以下操作:
myMap.compute(someKeyValue, (k, v) -> {v.add(new SomeOtherClass()); return v;});
Note:笔记:
Using compute
is analogous to the original snippet that assumes that somKeyValue
is present in the map.使用
compute
类似于假设somKeyValue
存在于 map 中的原始片段。 Using computeIfPresent
is probably safer, though.不过,使用
computeIfPresent
可能更安全。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.