2017-06-19 3 views
1

私はiterator.next()を実行する行の後にこのコードがNullPointerExceptionをスローしない理由を理解していません。 Javadocは言う:ConcurrentHashMapでのNullPointerExceptionが表示されない

ビューのiterator [..]彼ら 反復子の構築時に存在し、(ただし保証 ではありません)構築後のすべての変更を反映しているように要素を横断するために保証します。

すべての実行では、変更を反映しませんでした。そうしないと、cur.getKey()は要素を削除したので、NullPointerExceptionを返します。私はエラーを容易にするために寝る。

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.concurrent.ConcurrentHashMap; 

class MapWorker implements Runnable { 
    private final ConcurrentHashMap<Integer, String> map; 

    public MapWorker(final int i, final ConcurrentHashMap<Integer, String> map) { 
     this.map = map; 
    } 

    @Override 
    public void run() { 
     // Set key and value to search for 
     final Integer key = 3; 
     final String value = "three"; 

     final Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator(); 
     System.out.println("Map is " + map); 
     while (iterator.hasNext()) { 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      final Entry<Integer, String> cur = iterator.next(); 

      if (cur.getKey()==key && cur.getValue().equals(value)) { 
       iterator.remove(); 
       System.out.println("Removed"); 
      } 
     } 
    } 
} 

public class MapExercise { 
    static final int NUM_WORKERS = 5; 

    public static void main(final String[] args) { 
     // Create and populate map 
     final ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<Integer, String>(); 
     map.put(1, "one"); 
     map.put(2, "two"); 
     map.put(3, "three"); 
     map.put(4, "four"); 
     map.put(5, "five"); 

     // Create and init worker threads 
     final List<Thread> allThreads = new ArrayList<Thread>(); 
     for (int i = 0; i < NUM_WORKERS; i++) 
      allThreads.add(new Thread(new MapWorker(i, map))); 

     // Start worker threads 
     System.out.println("---------------------------"); 
     for (final Thread t : allThreads) 
      t.start(); 

     // Wait for worker threads to finish 
     for (final Thread t : allThreads) 
      try { 
       t.join(); 
      } catch (final InterruptedException e) { 
       /* do nothing */ 
      } 
     System.out.println("---------------------------"); 
     System.out.println(map); 
    } 
} 

答えて

0

iterator.hasNext()がtrueを返す限り、まだ要素があります。そのため、あなたはNullPointerExceptionを受け取っていません。

+0

はiterator.hasNext()がtrueを返すと言います。一方、別のスレッドは番号3を削除します。これはイテレータの次の要素であったはずです。コンテキストはすでにwhile(iterator.hasNext())に入った前のスレッドに戻ります。 iterator.next()は何を返しますか?どのようなものが返っても、私は例外をスローするべきものです。 – Christian

0

あなたはConcurrentHashMap上のドキュメントを読んでくださいなのputAllとクリア、同時 回収のなどの集計操作について

だけでいくつかのエントリの挿入や削除を反映することができます。 同様に、イテレータ、スプリッタおよび列挙は、 イテレータ/列挙の作成時またはその後のある時点におけるハッシュテーブルの状態を反映する要素 を返します。彼らは ConcurrentModificationExceptionをスローしません。ただし、イテレータは一度に1つのスレッドのみが使用する に設計されています。

基本的に、イテレータはマップの古いバージョンを表示しますが、「実際の」マップは一連の変更を受けている可能性があります。

あなたはこの前イテレータを通してそれを取り除くための鍵の存在をテストすることによって、ケースであることを自分自身を納得させることができます。

 if (cur.getKey()==key && cur.getValue().equals(value)) { 
      boolean exists = map.containsKey(cur.getKey()); 
      iterator.remove(); 
      System.out.println("Removed: " + exists); 
     } 
関連する問題