2017-06-19 48 views
1

我不明白爲什麼這段代碼不會拋出一個NullPointerException後行我iterator.next();的JavaDoc說:預期NullPointerException異常與ConcurrentHashMap不顯示

視圖的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清晰,同時 檢索可能只反映了某些條目的插入或刪除。 類似地,Iterators,Spliterator和Enumerations返回元素 ,反映了迭代器/枚舉創建時或之後的某個時刻哈希表的狀態。他們不會拋出 ConcurrentModificationException。但是,迭代器被設計爲一次僅由一個線程使用的 。

它基本上意味着迭代器看到舊版本的地圖,而「真實」地圖可能已經過一系列修改。

可以說服自己,這是由密鑰之前是否存在通過迭代器取出測試的情況:

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