将ConcurrentHashMap复制到HashMap不一致

时间:2014-03-11 14:51:22

标签: java multithreading copy concurrenthashmap atomicinteger

我试图做以下事情:

  1. 我的程序启动线程,从AtomicInteger增加ConcurrentHashMap<String, AtomicInteger>并将新Integer添加到ConcurrentHashMap<String, CopyOnWriteArrayList<Integer>>。在这种情况下,CopyOnWriteArrayList的大小等于AtomicInteger的值(当然对于具有相同键的条目)
  2. 完成所有主题后(CountDownLatch完成后)我尝试将ConcurrentHashMap<String, AtomicInteger>转换为HashMap<String, Integer>,以便按地理位置排序,因为AtomicInteger无法比较
  3. 转换后,我按值排序HashMap并选择20个值最高的条目 - 在排序后的地图中,它们是前20个条目。
  4. 最后,我将值打包到List中,并使用GSON生成JSON字符串。
  5. 问题

    我的期望:由于我使用了AtomicIntegerConcurrentHashMapCopyOnWriteArrayList我希望所有具有相同键的条目的所有大小和值都相等,即使在我的JSON字符串中也是如此像:

    myAtomcIntegerConcurrentHashMap.get("ABC").intValue() == 
    myCOWArrayListConcurrentHashMap.get("ABC").size() == 
    myNewHashMap.get("ABC")
    

    但结果似乎有所不同。我做了一些控制台输出来测试我的值并得到以下结果:

    ConcurrentHashMap复制到HashMap时,我会再次验证我的值。每次&#34;坏复制&#34;值是不同的(对于下面的代码片段):

     COWArrayList.size  AtomicInteger.intValue  Value in new HashMap
     299                299                     298
     122                122                     121
    

    之后,我再次在我的新HashMap上再迭代4次以再次比较我的值,每次我得到新的随机数&#34;糟糕复制&#34;值(注意,复制时未检测到值)(对于下面的代码片段):

     COWArrayList.size  AtomicInteger.intValue  Value in new HashMap  Common Key
     849                849                     827                   CGCCACC
     838                838                     813                   GGTGGTG
    

    我的Json也不正确。例如。对于Json中我的数组的键"CGCCACC"大小为887,与上表(849)不同。

    以下是我使用的代码段(其中一些来自StackOverflow):

    在我的主题中增加AtomicInteger并向CopyOnWriteArrayList添加新的整数:

    //Add new Integer 'position' to the COWArrayList from 'positions' with the key 'frame'
    List<Integer> copyArr = positions.get(frame);
    if (copyArr == null) {
      copyArr = new CopyOnWriteArrayList<Integer>();
      List<Integer> inMap = positions.putIfAbsent(frame, (CopyOnWriteArrayList<Integer>) copyArr);
      if (inMap != null) copyArr = inMap; // already in map
    }
    copyArr.add(position);
    
    //Increment the AtomicInteger from 'scores' with the key 'frame'
    AtomicInteger value = scores.get(frame);
    if (value==null){ 
      value = new AtomicInteger();
      AtomicInteger actual = scores.putIfAbsent(frame, value);
      if(actual != null) value = actual;
    }
    value.incrementAndGet();
    

    ConcurrentHashMap<String, AtomicInteger>复制到HashMap<String, Integer>每个值(我猜它非常低效)并立即验证:

    //init new, non-concurrent Map
    Map<String, Integer> myHashMap = new HashMap<String, Integer>();
    
    //iterate over the Map and copy each value from 'scores' to 'newHashMap'
    for(Map.Entry<String, AtomicInteger> score : scores.entrySet()){
      myHashMap.put(score.getKey(), score.getValue().intValue());
    
      //verify just added Value and print values of all Maps if something is wrong
      if(score.getValue().intValue() != myHashMap.get(score.getKey())){
        System.out.println(score.getValue().intValue() + " " + positions.get(score.getKey()).size() + " " + myHashMap.get(score.getKey()));
      }
    }
    

    再次验证myHashMap的复制值(此处我也随机获得&#34;错误复制&#34;值):

    for(Map.Entry<String, AtomicInteger> score : scores.entrySet()){
      if(score.getValue().intValue() != myHashMap.get(score.getKey())){
      System.out.println(score.getValue().intValue() + " = " + positions.get(score.getKey()).size() + " =? " + myHashMap.get(score.getKey()));
      }
    }
    

    为什么会发生这种情况,我的逻辑错过了什么?

    有关更多信息/代码等 - 请问。

    感谢您帮助我!

1 个答案:

答案 0 :(得分:1)

似乎AtomicInteger通过调用AtomicInteger.incrementAndGet()增量事件来解决问题。我的线程正在调用该函数〜3.5 Mio次,而Queue是巨大的。线程完成后,主线程立即复制ConcurrentHashMap的{​​{1}},但某些AtomicInteger的队列并不完整。这就造成了不一致。

我通过给AtomicIntegers一些时间来完成它来解决这个问题&#34;增加队列&#34;完成所有线程后。

AtomicInteger

瞧!没有不一致了!

如果有另一种方法等待 try { myCountDownLatch.await(); Thread.sleep(5000); //let AtomicInteger finish they incrementations } catch (Exception e) { System.err.println("Error in a Latch Countdown: " + e.toString()); } 完成增量队列,我会很感激阅读。