面试合集:https://gitee.com/mydb/interviewHashMap死循环是一个比较常见和经典的问题,在日常面试中经常出现,下面就用图带大家充分理解死循环的原因.JDK1.7版本就出现了pre-knowledgedeadloop问题。这个问题主要是HashMap自身的运行机制和并发操作导致的死循环。在JDK1.7中,HashMap的底层数据实现是一个数组+链表,如下图:而HashMap在添加数据的时候使用的是头部插入,如下图:HashMap在正常情况下的扩展实现为如下图所示:旧的HashMap的节点会依次转移到新的HashMap中。旧的HashMap的传递顺序是A、B、C,而新的HashMap采用的是头部插入的方式,所以新的HashMap中最终的顺序是C、B、A。如上图所示。有了这些前置知识,我们来看看死循环是怎么诞生的?死循环执行步骤1死循环是由HashMap并发扩容引起的。第一步并发扩容,线程T1和线程T2需要对HashMap进行扩容。此时T1和T2指向链表的头节点元素A。T1和T2的下一个节点,即T1.next和T2.next指向节点B,如下图:死循环执行步骤2死循环的第二步是线程T2时间片运行out和enter处于休眠状态,线程T1开始执行扩容操作,直到线程T1的扩容完成后线程T2才被唤醒。HashMap的顺序发生了变化,但是线程T2对发生的一切都是不可知的,因此它的指向元素保持不变。如上图所示,T2指向元素A,T2.next指向的节点为B元素。死循环执行步骤3当线程T1执行完毕,线程T2重新开始执行时,就建立了一个死循环,如下图:因为T1执行完展开后,B节点的下一个节点是A,第一个指向的节点tobyT2thread的节点是A,第二个节点是B,这个顺序刚好和T1展开后的节点顺序相反。T1执行完之后,顺序是从B到A,T2的顺序是从A到B,这样A节点和B节点就形成了死循环,这就是HashMap死循环的原因。解决方案HashMap死循环常见的解决方案有3种:使用线程安全的容器ConcurrentHashMap代替(推荐这种方案)。改用线程安全的容器Hashtable(性能低下,不推荐)。使用synchronized或者Lock对HashMap进行加锁后,操作相当于多线程队列执行(比较麻烦,不推荐)。综上所述,JDK1.7版本出现HashMap死循环。形成死循环的原因是HashMap在JDK1.7中使用了header插入方式。表头插入方式+链表+多线程并发+HashMap扩展。这些点加在一起就形成了,为了解决HashMap的死锁,可以改用线程安全的容器ConcurrentHashMap。判断是非在己,名誉在人,得失在数。公众号:Java面试真题解析
