引言
明天又是折磨人的一天,原本在钻研为什么ConcurrentHashMap为什么key和value为什么不能为null的问题的,后果百度查出来的答案有这么一个:
ConcurrentHashMap是平安失败机制的,使你此次读到的数据不肯定是最新的数据。无奈判断对应的key是不存在还是为空。
这看的我一愣一愣的,了解不能,就先写一下疾速失败和平安失败来坚固下知识点。
疾速失败
定义
在应用迭代器遍历一个对象时,遍历过程中对汇合内容进行了批改时,会抛出 Concurrent Modification Exception
原理
416行:HashMap源码外面有一个modCount计数器
显示下所有对于modCount的操作,能够看到只有自增操作,没有自减操作
1425行:迭代器结构的时候,先用另外的空间,保留modCount的值
1441行:HashMap提供的迭代器,比拟了modCount和expectedModCoun值是否相等,不相等就抛出异样
平安失败
定义
在应用迭代器遍历一个对象时,遍历过程中对汇合内容进行了批改时,不会抛出 Concurrent Modification Exception,且原有对象能批改胜利
原理
我原本是想写一下原理的,起初看了下平安失败代码汇合的源码,ConcurrentHashMap和HashTable,发现两者原理实现上还是有区别的。网络上查问平安失败机制广泛是这样形容的
平安失败是对汇合的拷贝进行遍历,遍历过程中对原汇合的批改不会被迭代器检测到
这个导致我认为ConcurrentHashMap获取迭代器的时候,也是拷贝了一份,后果花了大把的工夫看了ConcurrentHashMap的源码,发现压根找不到哪里有复制的。(基于jdk1.8)
ConcurrentHashMap代码测试平安失败(基于jdk1.8)
public static void main(String[] args) { ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>(16); concurrentHashMap.put("空想4", 4); concurrentHashMap.put("空想2", 2); concurrentHashMap.put("空想3", 3); Set<Map.Entry<String, Integer>> set = concurrentHashMap.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); concurrentHashMap.put("空想1", 1); } System.out.println("程序完结"); }
下面是我本人写的一个测试代码,运行下,用断点来看下具体发送了什么。
75行的断点,76行会加一个值进去,在75行的断点能够看到,set是3个值
通过一次76行当前,set的值就变成了4个,能够分明的看到ConcurrentHashMap相对不是对汇合的拷贝进行的遍历。上面贴上运行后果:
如果是对汇合的拷贝进行遍历,为什么还会输入遍历过程才退出的“空想1”呢?
具体为什么要看ConcurrentHashMap的源码来解释了,之后有空再写一篇ConcurrentHashMap的源码解析。
HashTable平安失败测试
public static void main(String[] args) { Hashtable<String, Integer> hashtable = new Hashtable<>(16); hashtable.put("空想4", 4); hashtable.put("空想2", 2); hashtable.put("空想3", 3); Set<Map.Entry<String, Integer>> set = hashtable.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); hashtable.put("空想1", 1); } System.out.println("程序完结"); }
下面是我的测试代码
这是运行后果,抛出了Concurrent Modification Exception。
我这么一看,不对啊,说好的平安失败是在复制的汇合上遍历的呢?怎么还呈现了疾速失败的异样?
兄弟们是不是想晓得?别急,我再丢个问题给你们思考下。
public static void main(String[] args) { Hashtable<String, Integer> hashtable = new Hashtable<>(16); hashtable.put("空想4", 4); hashtable.put("空想2", 2); hashtable.put("空想3", 3); Enumeration<String> keys = hashtable.keys(); while (keys.hasMoreElements()) { System.out.println(keys.nextElement()); hashtable.put("空想1", 1); } System.out.println("程序完结"); }
对之前的代码批改下迭代器,用了个HashTable自带的一个非凡迭代器,运行后果如下
哎,这么一看就变成和ConcurrentHashMap的迭代后果差不多了。
论断
我也不晓得怎么下结论,如果平安失败机制真的要拷贝一份的话,我感觉ConcurrentHashMap和HashMap都不是走平安失败机制。
ps:ConcurrentHashMap源码挖坑
pps:HashTable源码挖坑