HashMap Simple source and multi-threaded dead loop

Source: Internet
Author: User
Tags array length rehash

Main record HashMap Some basic operation of the source code implementation principle and multi-threaded case get () operation of the Dead loop cause

I. Introduction of HASHMAP

The main properties and methods of 1.HASHMAP collections

(default initialization capacity) Default_initial_capacity = 16

(default maximum capacity) Maximum_capacity = 1 << 30

(default load factor) Default_load_factor = 0.75f

(Entry array) entry[] Table

(Number of entry instances) size

Put (K key, V value) method

Get (K key) method

2.HASHMAP structure and operation (new method Put method get method):

The form of an array + list, stored in the form of an instance entry<k,v>

A.new Method :

We can see that a hashmap is an array structure, and when a new HashMap is created, an array is initialized (default length 16, load factor 0.75):

Source:

    /**      * Constructs an empty <tt>HashMap</tt> with the default initial capacity     * (+) and the default L Oad factor (0.75).      */     Public HashMap () {        this. loadfactor = default_load_factor;          = (int) (default_initial_capacity * default_load_factor);         New entry[default_initial_capacity];        Init ();    }

Example: table[0],table[1],table[2],table[3]...table[15]

B.put method

When the Put method is executed, the hash value of the key value is calculated first, the hash value and (the value of the array length minus one) are computed, the array subscript value is given, and the key value pair is placed in the array as a entry instance:

Put method source code:

    /*** Associates The specified value with the specified key on this map.     * If The map previously contained a mapping for the key, the old * value is replaced. *     * @paramkey key with which the specified value was to be associated *@paramvalue value to being associated with the specified key *@returnthe previous value associated with <tt>key</tt>, or * <tt>null</tt> if there is     No mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <TT>     ;null</tt> with <tt>key</tt>.) */     Publicv put (K key, V value) {if(Key = =NULL)            returnPutfornullkey (value); inthash = hash (Key.hashcode ());//calculates the hash value of a key        inti = indexfor (hash, table.length);//computes the array position based on the hash value and the group length         for(entry<k,v> e = table[i]; E! =NULL; E =e.next) {//If you encounter a hash conflict (E is not empty), traverse the linked listObject K; if(E.hash = = Hash && (k = e.key) = = Key | | key.equals (k))) {//If you encounter a key value equal, replace it.V OldValue =E.value; E.value=value; E.recordaccess ( This); returnOldValue; }        }
Indexfor method source code (computed array subscript), method and simple, the key value of the hash value and array length-1 did and operation
    /**      * Returns index for hash code h.      */    Static int indexfor (intint  length) {        return H & (Length-1) ;    }

Example: Add a key value pair is 7, 77, call method Put (7,77), 7 after the calculated hash value of 7 (can be self-validating, do not explain), call the Indexfor method and operation: 0111&1111=0111, subscript value is 7.

TABLE[0],TABLE[1],TABLE[2],TABLE[3]...TABLE[7]=7...TABLE[15]

Add Canadian 8,put (8,88), 15 after the calculated hash value is still 8,1000&1111=1000, the subscript value is 8.

TABLE[0],TABLE[1],TABLE[2],TABLE[3]...TABLE[7]=7,TABLE[8]=8...TABLE[15]

Tim 22,put (22,2222), 22 after the calculated hash value is 23,10111&1111=7, the subscript value is 7, at this time due to the presence of table[7] element (7,77), resulting in a hash conflict, HashMap will put 23 into table[7] and then execute (e=e.next) to point the next pointer to the previous element (7,77) in the form of a list, as shown in:

When the number of entry exceeds the maximum capacity value * load factor (16*0.75=12), HashMap enters the resize method, re-creates an array and expands to twice times the original, then copies the data to the new array as shown in:

Resize method source code:

    /*** Rehashes The contents of this map to a new array with a * larger capacity.     This method was called automatically when the * number of the keys on this map reaches its threshold. * * If current capacity are maximum_capacity, this method does isn't * resize the map, but sets threshold to Integer.     Max_value.     * This have the effect of preventing future calls. *     * @paramnewcapacity The new capacity, must be a power of; * Must be greater than current capacity unless current * capacity are maximum_capacity (in which case Val     UE * is irrelevant). */    voidResizeintnewcapacity) {entry[] oldtable=table; intOldcapacity =oldtable.length; if(Oldcapacity = =maximum_capacity) {Threshold=Integer.max_value; return; } entry[] NewTable=NewEntry[newcapacity];        Transfer (newtable); Table=newtable; Threshold= (int) (Newcapacity *loadfactor); }

C.get Method:

When the Get method is executed, the array subscript is obtained according to the hash value of the key value, and the key value of the entry in the array is compared with the parameter in the get (if there is a linked list within the array, the list will continue to be traversed), and if the hash is equal and equals is returned.

Get method source code:

   /*** Returns the value to which the specified key is mapped, * or {@codeNULL} If this maps contains no mapping for the key. * * <p>more formally, if this map contains a mapping from a key * {@codek} to a value {@codeV} such that {@code(key==null k==null: * key.equals (k))}, then this method returns {@codev}; otherwise * it returns {@codenull}.     (There can is at the most one such mapping.) * * <p>a return value of {@codenull} does not <i>necessarily</i> * indicate this map contains no mapping for the key; It ' s also * possible that the map explicitly maps the key to {@codenull}. * The {@link#containsKey ContainsKey} operation is used to * distinguish these and cases. *     * @see#put (Object, Object)*/     PublicV get (Object key) {if(Key = =NULL)            returnGetfornullkey (); inthash = hash (Key.hashcode ());//Calculate hash value         for(Entry<k,v> e =table[indexfor (hash, table.length)]; E!=NULL; E=e.next) {//this iterates through the list of links in the array and returns if the key value is found to be equal.Object K; if(E.hash = = Hash && (k = e.key) = = Key | |Key.equals (k))) returnE.value; }        return NULL; }


Second, Java multi-threaded HashMap dead loop

excerpt from:http://blog.csdn.net/xiaohui127/article/details/11928865The process of normal rehash

I drew a picture and made a presentation.

    • I assume that our hash algorithm simply uses the key mod to size the table (that is, the length of the array).
    • The top is the old hash table, where the hash table is size=2, so key = 3, 7, 5, after mod 2 all conflict in table[1] here.
    • The next three steps are the hash table resize into 4, and then all <key,value> re-rehash the process
rehash under the concurrency

1) Suppose we have two threads. I marked it in red and light blue.

Let's look back at this detail in our transfer (Resize method) code:

                 Do {                    Entry///  <--assumes that a thread is scheduled to be dispatched to suspend  the                    int i = indexfor (E.hash, newcapacity);                     = Newtable[i];                     = E;                     = Next;                  while null);

And our thread two execution is done. So we have the following look.

Note that because Thread1 's e points to key (3), and next points to key (7), after thread two rehash, it points to the linked list of threads two reorganization . We can see that the order of the linked list is reversed.

2) The line Cheng is dispatched back to execute.

    • First executes newtalbe[i] = e;
    • Then E = Next, which led to the E pointing to Key (7),
    • The next loop, next = E.next, causes next to point to key (3).

3) All is well.

Line Cheng went on to work. Take the key (7) down, put it on the first one of Newtable[i], and move E and next down .

4) Ring link appears.

E.next = Newtable[i] Causes key (3). Next points to key (7)

Note: At this point the key (7). Next has pointed to key (3), and the ring list appears.

So, when our thread was called to Hashtable.get (11), the tragedy appeared--infinite Loop.

HashMap Simple source and multi-threaded dead loop

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.