简体   繁体   English

Java - 如何对并发 map 的值进行原子操作?

[英]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.但是,不能保证在getadd指令之间,其他一些线程不会修改结构,干扰第一个执行。

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 (或computeIfAbsentcomputeIfPresent )的整个方法调用是原子完成的。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM