【问题标题】:Map concurrency with mutable keys使用可变键映射并发
【发布时间】:2014-02-24 17:09:10
【问题描述】:

我有: Map<K1, Map<K2, V>>,其中:

  1. K1 是可变的。 (它很少改变,而且只在一个地方改变,所以我可以删除 K1 的 Map 并用另一个键重新设置)

我想要: 使地图并发。我要同时:

  1. 修改 K2 的值 (V)
  2. 将整个地图替换为 K1

更新问题:下面的代码容易出错吗?

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!
}

【问题讨论】:

  • 应该返回什么map.get(null)
  • @nachokk 也是实体地图
  • 在没有大量锁的情况下,很难实现嵌套可变数据结构的并发性。
  • 另外,请注意 HashMap 中键的可变性非常危险。如果对象发生变化,则不会重新计算地图中关键对象的位置。
  • (i) 可变键是个坏主意,在并发结构中更是如此 (ii) 默认替换 null K1 NULL = new K1(someSpecificValue);

标签: java collections map concurrency


【解决方案1】:

此代码受制于竞争条件。

多个线程可以检测到map.get(v.k1) == null。根据执行顺序,其中一个线程可以为k1 分配一个新的子图,并破坏其他线程已经添加了它们的值的子图。

ConcurrentMap 更突出的特点之一是它的putIfAbsent() 方法。

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

【讨论】:

  • 请看removeValue方法。为什么我不能删除值。为什么我不能在 changeK1 方法中添加它们?
  • 你怎么知道你不能?什么是你的测试来查看一个值是否被删除,或者一个值是否被改变?
  • @VolodymyrBakhmatiuk ?
  • 请执行我的延迟。我在调试器中检查它。
  • @VolodymyrBakhmatiuk 它对我有用。如果在删除 k2->value 条目后子图为空,则您没有任何东西可以删除子图。这就是让你困惑的地方吗?如果您需要更多帮助,请发布说明问题的SSCCE。问题中的当前代码甚至无法编译。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 2013-06-28
  • 2023-03-29
  • 2012-01-23
  • 2015-07-18
  • 1970-01-01
  • 2018-07-28
相关资源
最近更新 更多