Java HashMap.get(Object) infinite loop

后端 未结 3 454
温柔的废话
温柔的废话 2021-02-03 23:23

A few answers on SO mention that the get method in a HashMap can fall into an infinite loop (e.g. this one or this one) if not synchronized properly (and usually the bottom line

3条回答
  •  南方客
    南方客 (楼主)
    2021-02-03 23:52

    Situation:

    The default capacity of HashMap is 16 and Load factor is 0.75, which means HashMap will double its capacity when 12th Key-Value pair enters in the map (16 * 0.75 = 12).

    When 2 thread tries to access HashMap simultaneously, then you may encounter infinite loop. Thread 1 and Thread 2 tries to put 12th key-value pair.

    Thread 1 got execution chance:

    1. Thread 1 tries to put 12th key-value pair,
    2. Thread 1 founds that Threshold limit is reached and it creates new Buckets of increased capacity. So map's capacity is increased from 16 to 32.
    3. Thread 1 now transfers all existing key-value pairs to new buckets.
    4. Thread 1 points to first key-value pair and next(second) key-value pair to start transfer process.

    Thread 1 after pointing to key-value pairs and before starting the transfer process, loose the control and Thread 2 got a chance for execution.

    Thread 2 got execution chance:

    1. Thread 2 tries to put 12th key-value pair,
    2. Thread 2 founds that Threshold limit is reached and it creates new Buckets of increased capacity. So map's capacity is increased from 16 to 32.
    3. Thread 2 now transfers all existing key-value pairs to new buckets.
    4. Thread 2 points to first key-value pair and next(second) key-value pair to start transfer process.
    5. While transferring key-value pairs from old buckets to new buckets, key-value pairs will be reversed in new buckets because hashmap will add key-value pairs at the start and not at the end. Hashmap adds new key-value pairs at start to avoid traversing linked list every time and keep constant performance.
    6. Thread 2 will transfer all key-value pairs from old buckets to new buckets and Thread 1 will get chance for execution.

    Thread 1 got execution chance:

    1. Thread 1 before leaving control was pointing to first element and next element of old bucket.
    2. Now when Thread 1 started putting key-value pairs from old bucket to new bucket. It successfully puts (90, val) and (1, val) in new Bucket.
    3. When it tries to add next element of (1, val) which is (90, val) into new Bucket, it will end up in infinite loop.

    Solution:

    To solve this either use a Collections.synchronizedMap or ConcurrentHashMap.

    ConcurrentHashMap is thread-safe that is the code can be accessed by single thread at a time.

    HashMap can be synchronized by using Collections.synchronizedMap(hashMap) method. By using this method we get a HashMap object which is equivalent to the HashTable object. So every modification is performed on Map is locked on Map object.

提交回复
热议问题