ConcurrentHashMap的预期NullPointerException不会显示

时间:2017-06-19 00:22:07

标签: java concurrency iterator concurrenthashmap

我不明白为什么这段代码在我执行iterator.next()的行之后不会抛出NullPointerException。 JavaDoc说:

  

视图的迭代器[..]保证遍历元素   在构造迭代器时存在,并且可能(但不是   保证)反映施工后的任何修改。

在我执行的所有运行中,它从未反映任何修改,否则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);
    }
}

2 个答案:

答案 0 :(得分:0)

只要iterator.hasNext()返回true,就会有一个元素。这就是你没有收到NullPointerException的原因。

答案 1 :(得分:0)

您应该阅读ConcurrentHashMap上的文档:

  

对于putAll和clear,concurrent等聚合操作   检索可能反映只插入或删除一些条目。   同样,Iterators,Spliterators和Enumerations返回元素   反映哈希表的状态在某个时刻或之后的某个时刻   创建迭代器/枚举。他们不扔   ConcurrentModificationException的。但是,迭代器的设计是   一次仅由一个线程使用。

它基本上意味着迭代器会看到旧版本的地图,而#34;真实的&#34;地图可能已经过一系列的修改。

您可以通过在通过迭代器删除密钥之前测试密钥的存在来说服自己:

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