2

私は次のことをしようとしています:

  1. AtomicInteger私のプログラムは、 fromをインクリメントし、 newを にConcurrentHashMap<String, AtomicInteger>追加するスレッドを開始します。その場合、 のサイズはの値と等しくなります (もちろん、同じキーを持つエントリの場合)。IntegerConcurrentHashMap<String, CopyOnWriteArrayList<Integer>>CopyOnWriteArrayListAtomicInteger
  2. すべてのスレッドが完了した後 (が終了したとき) 、そのマップを値でソートするためにCountDownLatch変換しようとします。比較できないためです。ConcurrentHashMap<String, AtomicInteger>HashMap<String, Integer>AtomicInteger
  3. 変換後、値で並べ替え、HashMap値が最も高い 20 エントリを選択します。並べ替えられたマップでは、それらは最初の 20 エントリです。
  4. 最後に、値をリストにパックし、GSON で JSON 文字列を作成します。

問題

私が期待すること: の使用により、AtomicInteger同じ キーを持つすべてのエントリのすべてのサイズと値が、次のような JSON 文字列であっても等しいと予想されます。ConcurrentHashMapCopyOnWriteArrayList

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

しかし結果は違うようです。値をテストするためにいくつかのコンソール出力を作成したところ、次の結果が得られました。

ConcurrentHashMapからにコピーしている間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();

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(ここでは、ランダムな「不適切なコピー」値も取得します):

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 回呼び出しており、Queue は巨大です。私のスレッドが完了した後、メインのスレッドは即座にConcurrentHashMapofをコピーしAtomicIntegerますが、一部のキューは完全に完了し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 に答える