有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何对并发映射的值进行原子化操作?

假设我在一个类中有以下字段:

ConcurrentHashMap<SomeClass, Set<SomeOtherClass>> myMap = new ConcurrentHashMap<SomeClass, Set<SomeOtherClass>>();

该类的一个实例在多个线程之间共享

如果要从与键关联的集合中添加或删除元素,可以执行以下操作:

Set<SomeOtherClass> setVal = myMap.get(someKeyValue);
setVal.add(new SomeOtherClass());

get操作是原子的,因此是线程安全的。但是,不能保证在getadd指令之间,其他线程不会修改结构,从而干扰第一个线程的执行

让整个行动原子化的最好方法是什么

以下是我的想法,但我不认为这是非常有效的(或是最好地利用Java的结构):

我有一个ReentrantLock字段,所以我的类如下所示:

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块来实现一个操作有多大意义

有更好的办法吗


共 (1) 个答案

  1. # 1 楼答案

    ConcurrentHashMap保证compute(或computeIfAbsentcomputeIfPresent)的整个方法调用是原子化的。例如,你可以这样做:

    myMap.compute(someKeyValue, (k, v) -> {v.add(new SomeOtherClass()); return v;});
    

    注意:
    使用compute类似于假设somKeyValue存在于映射中的原始片段。不过,使用computeIfPresent可能更安全