赞
踩
1.这个是初始状态,同时map里面存储的值
- do {
- Entry<K,V> next = e.next; // <--假设线程一执行到这里就被调度挂起了,执行其他操作
- int i = indexFor(e.hash, newCapacity);
- e.next = newTable[i];
- newTable[i] = e;
- e = next;
- } while (e != null);
此时线程1的情况,此时线程扩容然后在准备开始给节点重新分配对应的数组的时候被挂起(这个e和next不懂得可以去了解下链表,e代表当前节点,next代表当前节点中存储的下一个节点的地址)
这里讲下为什么扩容成这样,因为链表是从第一个节点开始读的所以一开始处理的应该是key=3,然后key=3被存储到数组3的位置,然后遍历到下一个节点key=7,把7存储到数组3的位置,key=3的前面,为什么存储在前面?因为不用遍历到末尾,这样快。然后在处理key=9。
重点来了!!
于是一个环形链表就形成了,因为key=7的下一个节点是指向key=3的,但是key=3的节点又指向着key=7.
这样就是一个很经典hashMap线程不安全导致的循环依赖,因为是个循环链表,就会导致数组一直重复扩容,导致集合的一个无限大,但是JDK1.8的时候,把头插法改成了尾插法,同时引进了红黑树,当连续扩容32次的时候会转换成红黑树,解决这个循环依赖的问题,但是还是可能会引起各种线程不安全问题,所以在多线程情况下,尽量使用ConcurrentHashMap。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。