1.JDK1.7中HashMap多线程插入出现的死循环问题
HashMap的容量是有限的,多次元素插入后会使得HashMap达到一定饱和度,Key映射位置发生hash冲突的几率会提高。此时,HashMap需要扩展它的长度,也就是进行resize操作。
衡量HashMap是否需要进行resize的条件为:HashMap.size() >= Capacity * LoadFactor,其中Capacity为原来的HashMap的长度,LoadFactor为负载因子(默认为0.75)。
HashMap经过resize扩容会创建一个新的Entry空数组,长度是原数组的2倍(初始状态下HashMap容量为16)。扩容后HashMap还需要进行rehash操作,hash公式为:index = hashcode(key)& (length - 1)。
resize之前的HashMap:
resize之后的HashMap:
在多线程情况下: 假设一个HashMap已经到了resize的临界点。此时有两个线程A和B,在同一时刻对HashMap进行put操作,由于Java7中采用头插法解决hash冲突,在rehash过程中,A、B两个线程在可能会形成链表环,造成死循环。
2.为什么JDK8中的HashMap仍是线程不安全的?
在JDK8中,采用拉链法解决hash冲突时,尽管采用尾插法代替头插法,但是使用HashMap并不只是仅仅用来插入数据,诚然1.8解决了死链问题,但是在多线程情况下还是有可能修改HashMap。比如多个线程同时修改HashMap中的某个Key的值,先前的那个线程修改的值可能被之后的线程修改覆盖掉,那么HashMap就不是线程安全了。
所以在Java8中HashMap只是在多线程下插入数据安全,但是修改并不线程安全的。