2

我正在尝试执行以下操作:

  1. 我的程序启动线程,增加一个AtomicIntegerfromConcurrentHashMap<String, AtomicInteger>并添加 new Integerto ConcurrentHashMap<String, CopyOnWriteArrayList<Integer>>。在这种情况下,的大小CopyOnWriteArrayList等于的值AtomicInteger(当然对于具有相同键的条目)
  2. 在所有线程完成后(CountDownLatch完成后),我尝试转换ConcurrentHashMap<String, AtomicInteger>HashMap<String, Integer>按值对 Map 进行排序,因为AtomicInteger不可比较。
  3. 转换后,我HashMap按 Values 排序并选择 20 个具有最高值的条目 - 在排序后的 Map 中,它们是前 20 个条目。
  4. 最后,我将值打包到一个列表中,并使用 GSON 制作 JSON 字符串。

问题

我的期望:由于我使用AtomicInteger,ConcurrentHashMap并且CopyOnWriteArrayList 我希望具有相同键的所有条目的所有大小和值都是相等的,即使在我的 JSON 字符串中,例如:

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

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

ConcurrentHashMap在从to复制时,HashMap我再次验证我的值。每次“错误复制”的值都不同(代码片段如下所示):

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

之后,我在我的新值上再迭代 4 次HashMap以再次比较我的值,并且每次我得到新的随机“错误复制”值(注意,复制时未检测到值)(代码片段如下所示):

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

我的 Json 也不正确。例如"CGCCACC",我在 Json 中的数组的密钥大小是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();

复制 fromConcurrentHashMap<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(这里我也得到随机的“错误复制”值):

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()));
  }
}

为什么会发生这种情况,我是否错过了逻辑中的某些内容?

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

感谢你们对我的帮助!

4

1 回答 1

1

似乎AtomicInteger通过调用AtomicInteger.incrementAndGet()增量事件来查询。我的线程正在调用该函数〜 3.5 Mio 次,并且队列很大。在我的线程完成后,主线程会立即复制 的ConcurrentHashMapAtomicInteger但一些队列AtomicIntegers并没有完全完成。这使得不一致。

我通过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());
    }

瞧!再也没有矛盾了!

如果有另一种方法可以等待AtomicInteger完成他们的增量队列,我会很感激阅读。

于 2014-03-11T18:37:28.970 回答