A probe into the HashMap death cycle

Source: Internet
Author: User

As we all know, HashMap uses the chain list to solve the hash conflict, the specific HashMap analysis can refer to http://zhangshixi.iteye.com/blog/672697 analysis. Because it is a linked list structure, it is easy to form a closed link, which creates a dead loop at the time of the loop. But what I'm curious about is how this closed link is formed. In single-threaded situations, it is impossible to generate a closed loop if only one thread operates on the HASHMAP data structure. That is only in the case of multithreading concurrency, that is, when put operation, if Size>initialcapacity*loadfactor, then this time HashMap will be rehash operation, The structure of the HashMap will be changed dramatically. It is possible that the rehash operation was triggered at this time by two threads, resulting in a closed loop. Below we from the source code step by step analysis of how this circuit is produced. Let's take a look at the put operation:

 Publicv put (K key, V value) {if(Key = =NULL)          returnPutfornullkey (value); inthash =Hash (Key.hashcode ()); inti =indexfor (hash, table.length); //There is a key, replace the old value     for(entry<k,v> e = table[i]; E! =NULL; E =e.next) {Object k; if(E.hash = = Hash && (k = e.key) = = Key | |Key.equals (k))) {V OldValue=E.value; E.value=value; E.recordaccess ( This); returnOldValue; }} Modcount++; //Table[i] is empty, then directly generate a new entry placed on Table[i]addentry (hash, key, value, I); return NULL; }  

AddEntry Operation:

void addentry (intint  bucketindex) {  ry<K,V> e = Table[bucketindex] ;       New Entry<k,v>(hash, key, value, e);       if (size++ >= threshold)          Resize (2 * table.length);  }  

As you can see, if size now exceeds threshold, then resize operation is necessary:

voidResizeintnewcapacity) {entry[] oldtable=table; intOldcapacity =oldtable.length; if(Oldcapacity = =maximum_capacity) {Threshold=Integer.max_value; return; } entry[] NewTable=NewEntry[newcapacity]; //transfer data from the old entry array to the new entry arraytransfer (newtable); Table=newtable; Threshold= (int) (Newcapacity *loadfactor); }  

Take a look at the transfer operation, the closed loop is generated here:

voidtransfer (entry[] newtable) {entry[] src=table; intNewcapacity =newtable.length; /** During the conversion process, HashMap is equivalent to reversing the order of the elements on the original linked list. * For example, a entry[i] on the list of the order is e1->e2->null, then after the operation * becomes the E2->e1->null*/           for(intj = 0; J < Src.length; J + +) {Entry<K,V> e =Src[j]; if(E! =NULL) {Src[j]=NULL;  Do {                      //I think this is the culprit for the death cycle.Entry<k,v> next =E.next; inti =indexfor (E.hash, newcapacity); E.next=Newtable[i]; Newtable[i]=e; E=Next; }  while(E! =NULL); }          }      } 

So how is the loop generated, the problem is in the Next=e.next this place, in the context of multi-threaded concurrency, in order to facilitate the analysis, we assume that two threads p1,p2. Src[i] The list order is e1->e2->null. We separate the execution of thread p1,p2.

First, P1, and P2 into the For loop, where the local variables are as follows in thread P1 and P2:

E Next
P1 E1 E2
P2 E1 E2

At this point the order of the two entry is still the first state e1->e2->null, but at this point the P1 may be paused for some reason, P2 will continue to execute, and the Do-while loop is completed. At this time the order of entry becomes e2->e1->null. After waiting for P2 to execute, it might be P1 to continue, when the value of the local variable e in the P1 thread is E2 (note that the order of two elements in memory becomes e2->e1->null), and the following P1 thread enters the Do and loop. At this time the P1 thread finds the location of E1 in the new entry array,

E.next = Newtable[i];   = e;  

The following assigns next to E, when the value of E becomes E2 and continues the next cycle, when

E Next
P1 E2 E1

E2->next=e1, this is the "credit" of thread P2. After the program executes this cycle, e=e1,

Continue the third cycle, at this time according to the algorithm, it will be e1->next=e2.

In this way, the e1->next=e2 is executed in the thread P1, and E2->next=e1 is executed in the thread P2, thus forming a ring. At the time of the get operation, the next value is never null, resulting in a dead loop.

In fact, when I first came across this statement, I was also startled, hashmap how the problem will arise, careful analysis, the problem is high concurrency scenario is very easy to appear. Sun's engineers suggested that Concurrenthashmap should be used in such a scenario. Specific reference http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6423457.

Although the problem has not been encountered in normal work, but should be noted later. To choose the right class in different scenarios, avoid the problem of the dead loop like HashMap.

A probe into the HashMap death cycle

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.