专注于Java、Golang、软件架构、项目管理

Back

jdk7hashmap死循环问题#

在多线程并发环境下。不应该用此容器,而应使用线程安全的容器如ConcurrentHashmap

其死循环主要是扩容的时候resize方法内调用的transfer方法导致。

e.next = newTable[i];
newTable[i] = e;
java

如果两个线程正在处理同一个节点e,那么第一个线程正常执行,但是第二个线程设置e.next=e,因为第一个线程已经将newTable[i]设置为e。节点e现在指向它自己,当调用get(Object)时,它将进入一个无限循环。无限循环则会导致cpu100%,另外因为节点形成了环形,后面的元素无法访问到导致数据丢失

而java8中,resize的时候保持了节点的顺序。但同样会有数据丢失的问题

jdk7与jdk8关于Hashmap的主要区别

1、jdk7中数据结构为:数组+链表 jdk8中数据结构为:数组+链表/红黑树 当链表数量大于8时,链表转化为红黑树

2、hash值的计算:jdk8采用高低16位异或来进行hashcode计算,可以尽量减少hash碰撞

3、链表的插入:jdk7采用头插法,扩容后元素位置相反。jdk8中采用尾插法,扩容后元素位置一致

ConcurrentHashmap#

put源码中,Unsafe,CAS的操作,都是线程安全的,保证了只有一个线程可以在这里成功的将一个key-value对方在数组的一个地方里。如果多个线程并发来执行put的操作,都走到这里,可能就会有其他的线程,CAS往数组里赋值操作就会失败,如果CAS成功了,此时就直接break掉,put操作就成功了

get类似,使用Unsafe保证线程安全。Node的val是volatile的,保持了多线程可见性

扩容,扩容时使用

对于get、size、遍历 这些操作,都是弱一致性的