"Java concurrency" causes hashmap non-thread-safe

Source: Internet
Author: User

0. Write in front

In one of my summary thread-scoped shared data articles, I used HashMap to store data in different threads for data to be used in thread range, key is the current thread and value is the data in the current thread. When I fetch it, I take it from the HashMap according to the current thread name.
Because the original learning HashMap and Hashtable source, know Hashtable is thread-safe, because the method used in the synchronized synchronization, but HashMap no, so hashmap is non-thread-safe. In the above mentioned example, I would like to not modify HashMap, only need to take the value from it, so there is no thread security problem, but I ignored a step: I have to put the different threads of data into the HashMap, the existence of the problem may occur, Although I saved the key using a different thread name, in theory, it will not conflict, but this design or thought is not rigorous. This is also due to a netizen saw my article after I put forward the question, I later carefully examined the next, re-review the source of the next hashmap, coupled with some information on-line check, here to summarize hashmap in the end when there may be a thread safety problem.
We know that the HashMap is a entry array, and when a hash conflict occurs, the HashMap is solved by a linked list, and the head node of the list is stored in the corresponding array position. For linked lists, the newly added nodes are added from the beginning node. There is a description of HashMap in Javadoc:

This implementation is not synchronous. If more than one thread accesses a hash map at the same time, and at least one of the threads modifies the mapping from the structure, it must remain externally synchronized. (Structural modification is any action that adds or deletes one or more mapping relationships; changing only the values associated with the key that the instance already contains are not structural modifications.) This is typically done by synchronizing the objects that naturally encapsulate the mapping. If such an object does not exist, you should use the Collections.synchronizedmap method to "wrap" the map. It is a good idea to do this at creation time to prevent unintended non-synchronous access to the mappings, as follows:
Map m = Collections.synchronizedMap(new HashMap(...));

As you can see, the solution to the HASHMAP thread-safety problem is simple, and here's a quick look at some of the areas where threading problems can occur.

1. When inserting data into the HashMap

The following method is called when HashMap does a put operation:

//Add entry to HashMapvoidAddEntry (intHash, K key, V value,intBucketindex) {if(Size >= threshold) && (NULL! = Table[bucketindex]) {Resize (2* table.length);//expansion twice timeshash = (NULL! = key)? Hash (key):0;    Bucketindex = Indexfor (hash, table.length); } createentry (hash, key, value, Bucketindex);}//Create a entryvoidCreateentry (intHash, K key, V value,intBucketindex) {entry<k,v> e = Table[bucketindex];Save the original entry in the table first    //Create a new entry in the table in this position, and hang the original entry to the next of the entryTable[bucketindex] =NewEntry<> (hash, key, value, E);//So each location in the table will always save only one newly added entry, the other entry is a hanging one, so hang up thesize++;}

Now if the a thread and the B thread enter addentry at the same time, and then calculate the same hash value corresponding to the same array position, because there is no data at this point, and then call Createentry on the same group location, two threads will get the current head node simultaneously. After a writes a new head node, B also writes a new header node, and the write operation of B overwrites the write operation of a to cause the write operation of a to be lost.

2. When the HashMap is enlarged

Or the above AddEntry method, there is a scaling operation, this operation will be reborn into a new capacity of the array, and then the original array of all key value pairs are recalculated and written to the new array, and then point to the newly generated array. Look at the source of the expansion:

//New capacity for table expansionvoidResizeintnewcapacity) {entry[] oldtable = table;//Save old table    intoldcapacity = Oldtable.length;//Save old capacity    //If the old capacity is already the default maximum capacity of the system, set the threshold to the maximum value for shaping, exit    if(oldcapacity = = maximum_capacity) {threshold = Integer.max_value;return; }//Create a table based on the new capacityentry[] NewTable =NewEntry[newcapacity];//Convert table to newtableTransfer (newtable, inithashseedasneeded (newcapacity)); Table = newtable;//Set threshold valueThreshold = (int) math.min (newcapacity * loadfactor, maximum_capacity +1); }

So the problem is, when multiple threads come in at the same time, when the total number is detected exceeding the threshold, the resize operation is called simultaneously, each generating a new array and rehash to the underlying array table of the map, and finally only the last thread-generated new array is assigned to the table variable. All other threads will be lost. And when some threads have already been assigned and other threads have just begun, it will be problematic to use a table that has already been assigned as the original array. Therefore, in the expansion of the operation may also cause some concurrency problems.

3. When deleting data from HashMap

The source code for deleting key-value pairs is as follows:

//Delete the entry according to the specified key and return the corresponding value PublicVRemove(Object key) {entry<k,v> E = Removeentryforkey (key);return(E = =NULL?NULL: E.value); }//According to the specified key, delete the entry and return the corresponding valueFinalEntry<k,v> Removeentryforkey (Object key) {if(Size = =0) {return NULL; }inthash = (Key = =NULL) ?0: hash (key);inti = indexfor (hash, table.length);      Entry<k,v> prev = table[i]; entry<k,v> e = prev; while(E! =NULL) {entry<k,v> next = E.next; Object K;if(E.hash = = Hash && (k = e.key) = = Key | | (Key! =NULL&& Key.equals (k))) {modcount++; size--;if(prev = = e)//If a reference to the first item in the table is deletedTable[i] = next;//Direct the next reference in the first item to Table[i]            ElsePrev.next = Next;//Otherwise next in the previous entry of the current entry in Table[i] is placed in the current entryE.recordremoval ( This);returnE          } prev = e;      e = next; }returnE }

There are two types of thread safety problems that can occur when you delete this piece, the first being a thread that determines the specified array position I and enters the loop, at which point the other thread has deleted the data from the I position, and then the first thread is gone. But the deletion, the problem is not big.
Looking at another situation, when multiple threads operate the same array position at the same time, they will first obtain the current state of the location of the storage of the head node, and then each to carry out the calculation operation, and then write the results to the array location, in fact, when the other thread can be written back to this position has been modified, Will overwrite other threads ' modifications.
There are many other places there may be thread safety issues, I do not enumerate, in short, hashmap is non-thread-safe, in high-concurrency occasions, to use the Collections.synchronizedmap packaging. In addition, I have to thank the netizen, my understanding of HashMap thread safety is another step forward ~

-Willing to share and progress together!
-More articles please see: http://blog.csdn.net/eson_15

"Java concurrency" causes hashmap non-thread-safe

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.