VB_
VB_

Reputation: 45702

Map concurrency with mutable keys

I have: Map<K1, Map<K2, V>>, where:

  1. K1 is mutable. (It changes rarely and only in ine place, so I can just remove Map for K1 and set it again with another key)

I want: Make map concurrent. I want concurrently:

  1. Modify value (V) for K2
  2. Replace the whole Map for K1

UPDATED question: Is code below error prone?

public class V {
   K1 k1;
   K2 k2;

   final ConcurrentHashMap<K1, ConcurrentHashMap<K2, V>> map = new ConcurrentHashMap<K1, ConcurrentHashMap<K2, V>> ();

   public void changeK1(V v, K1 newK) {        
      removeValue(v); //doesn't remove old val!
      v.k1 = newK; //PROBLEM: map is the same as before `removeValue` call, but it shouldn't!
      addValue(V); //doesn't add new val!
   }

   void addValue(V v) {
      if (map.get(v.k1) == null) {
         map.put(v.k1, new ConcurrentHashMap<K2, V>());
      }
      map.get(v.k1).put(v.k2, v);
   }

   void removeValue(V v) {
      ConcurrentHashMap<v.k2, v> subMap = map.get(v.k1);
      if (subMap != null) {
         subMap.remove(v.k2); //remove from subMap but doesn't remove  from map!
   }
}

  //also I can remove any value by K1 or K2 at any moment!
}

Upvotes: 0

Views: 162

Answers (1)

erickson
erickson

Reputation: 269797

This code is subject to a race condition.

Multiple threads can detect that map.get(v.k1) == null. Depending on the order of execution, one of these threads can assign a new submap for k1 and clobber a submap to which other threads have already added their values.

One of the more prominent features of ConcurrentMap is its putIfAbsent() method.

map.putIfAbsent(v.k1, new ConcurrentHashMap<>());
map.get(v.k1).put(v.k2, v);

Upvotes: 1

Related Questions