Java ConcurrentHashMap不应出现NullPointerException';我没有出现

Java ConcurrentHashMap不应出现NullPointerException';我没有出现,java,concurrency,iterator,concurrenthashmap,Java,Concurrency,Iterator,Concurrenthashmap,我不明白为什么这段代码不在我执行iterator.next()的那一行之后抛出NullPointerException;JavaDoc说: 视图的迭代器[…]保证在元素运行时遍历它们 在构造迭代器时存在,并且可能(但不是) 保证)反映施工后的任何修改 在我所做的所有运行中,它从未反映任何修改,否则cur.getKey()会给我一个NullPointerException,因为我删除了一个元素。我甚至把睡眠,以促进错误 import java.util.ArrayList; import java

我不明白为什么这段代码不在我执行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);
    }
}
import java.util.ArrayList;
导入java.util.HashMap;
导入java.util.Iterator;
导入java.util.List;
导入java.util.Map.Entry;
导入java.util.concurrent.ConcurrentHashMap;
类MapWorker实现可运行的{
私有最终ConcurrentHashMap映射;
公共地图工作者(最终int i、最终ConcurrentHashMap地图){
this.map=map;
}
@凌驾
公开募捐{
//设置要搜索的键和值
最终整数键=3;
最终字符串值=“三”;
final Iterator Iterator=map.entrySet().Iterator();
System.out.println(“映射为”+Map);
while(iterator.hasNext()){
试一试{
《睡眠》(2000年);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
最终条目cur=iterator.next();
如果(cur.getKey()==key&&cur.getValue().equals(value)){
iterator.remove();
系统输出打印项次(“删除”);
}
}
}
}
公开课地图练习{
静态最终int NUM_工人=5;
公共静态void main(最终字符串[]args){
//创建并填充地图
最终ConcurrentHashMap=新ConcurrentHashMap();
地图放置(1,“一”);
图.put(2,“2”);
地图放置(3,“三”);
地图放置(4,“四”);
地图放置(5,“5”);
//创建和初始化工作线程
最终列表allThreads=newarraylist();
对于(int i=0;i
只要
迭代器.hasNext()
返回true,仍然存在一个元素。这就是为什么您没有收到NullPointerException。

只要
迭代器.hasNext()
返回true,就仍然有一个元素。这就是您没有收到NullPointerException的原因。

您应该阅读以下文档:

用于聚合操作,如putAll和clear、concurrent 检索可能只反映插入或删除某些条目。 类似地,迭代器、拆分器和枚举返回元素 反映哈希表在 创建迭代器/枚举。他们不会扔东西 ConcurrentModificationException。然而,迭代器被设计成 一次只能由一个线程使用

这基本上意味着迭代器看到了映射的旧版本,而“真实”映射可能经历了一系列修改

通过在通过迭代器删除密钥之前测试密钥的存在性,您可以确信情况就是这样:

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

您应该阅读以下文档:

用于聚合操作,如putAll和clear、concurrent 检索可能只反映插入或删除某些条目。 类似地,迭代器、拆分器和枚举返回元素 反映哈希表在 创建迭代器/枚举。他们不会扔东西 ConcurrentModificationException。然而,迭代器被设计成 一次只能由一个线程使用

这基本上意味着迭代器看到了映射的旧版本,而“真实”映射可能经历了一系列修改

通过在通过迭代器删除密钥之前测试密钥的存在性,您可以确信情况就是这样:

        if (cur.getKey()==key && cur.getValue().equals(value)) {
            boolean exists = map.containsKey(cur.getKey());
            iterator.remove();
            System.out.println("Removed: " + exists);
        }
假设迭代器.hasNext()返回true;同时(上下文切换)另一个线程删除数字3,它应该是迭代器的下一个元素。上下文返回到已进入while的上一个线程(iterator.hasNext())。iterator.next()返回什么?不管它返回什么,我都会在以后使用它,那个些应该抛出异常的东西;同时(上下文切换)另一个线程删除数字3,它应该是迭代器的下一个元素。上下文返回到已进入while的上一个线程(iterator.hasNext())。iterator.next()返回什么?不管它返回什么,我都会在以后使用它,那个些应该抛出异常的东西。