jdk1.7 HashMap 并发情况下不安全 容易造成一个循环列表

本文主要研究在并发的情况下,jdk1.7情况下出现的问题。

在我们使用HashMap的时候,无非就使用put和get方法,并发情况下put的时候就会出现问题。

jdk1.7 put 的源码

 

 

 

hashmap的数据结构是数组和链表的组成,上面的内容大概说的是,当数组不够的时候,要进行X2的扩容。

主要分析transfer的代码。比如原来的table的数,数据key=3,7,5

newTable 新的数组

table:原来的数组

 

 

 这是出现问题的代码

e.next=newTables[i];

newTables[i]=e;

e=next;

 

第一步:先分析单线程

1:fo循环第一步:table数组,e=(key=3),next =(key=7),int i=3。hash算法

  newTables[3]是null,所以e的next是null。

  把e放到了newTables[3]的位置。

  next这时变成了key=7。

 

2:for循环第二步:e=(key7),next =(key5),int i=3

  newTables[3]是key(3),所以e的next是key(3)。

  把e放到了newTables[3]的位置。

  next这时变成了key=5。

 

 

3:for循环第二步:e=(key=5),next =null,int i=1

  newTables[1]是null,所以e的next是null。

  把e放到了newTables[1]的位置。

  next这时变成了null。就跳出了循环。

 

单线程下面HashMap扩容,这是没有问题的。

 

 

在分析多线程下面的扩容。

有两个线程,当第一个线程执行到了 Entry<K,V> next = e.next;。由于该线程被挂起,第二个线程直接把扩容的操作进行完了。

直接把table变成了

 

 

 这时线程1继续往下执行

1:fo循环第一步:table数组,e=(key=3),next =(key=7),int i=3。hash算法

  newTables[3]是null,所以e的next是null。

  把e放到了newTables[3]的位置。

  next这时变成了key=7。

 

 

2:fo循环第二步:e=(key=7),next =(key=3),int i=3。hash算法

  newTables[3]是key=3,所以e的next是key=3。

  把e放到了newTables[3]的位置。

  next这时变成了key=3。

 

3:fo循环第三步:e=(key=3),next =null,int i=3。hash算法

  newTables[3]是key=7,所以e的next是key=7。

  把e放到了newTables[3]的位置。

  next这时变成了null。退出了循环

 

这个时候就出现了一个死循环的状态。

因为在内存当中,只存在一个对象的实例。key=7实例当中的next指向的是key=3。

而key=3指向的是key=7。从而造成了一个死循环的状态,形成一个循环列表。这也就是jdk1.7中出现的死循环。

 

在put的时候,并不能体现出来死循环的状态,当get一个不存在的key时候,就容易造成CPU100%

 

get操作的时候,如果e不等于null,就会一直找下一个next,直到找到为止。

当出现上面的问题,key=3的next指向key=7.而key=7的next指向key=3,CPU就会一直找,形成死循环。

 

注:上面只是个人的见解,如果有好的见解,往告知,谢谢!

posted @ 2019-07-22 16:35  陌然浅笑  阅读(290)  评论(0)    收藏  举报