Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashMap order changes when using Thread but is constant without Thread

I know that HashMap does not guarantee the order. Consider the following code:

import java.util.HashMap;
import java.util.Map;

public class SandBox {
    protected static class Book {
        String name;

        public Book(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    protected static class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            final int n = 10;
            Book[] books = new Book[n];
            for (int i=0; i<n; i++)
                books[i] = new Book("b" + i);
            for (Book b : books)
                System.out.print(b + ", ");
            System.out.println();
            HashMap<Book, Object> hm = new HashMap<>();
            for (Book b : books)
                hm.put(b, null);
            for (Map.Entry<Book, Object> entry : hm.entrySet())
                System.out.print(entry.getKey() + ", ");
            System.out.println();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread t = new MyThread();
        t.start();
        t.join();
    }
}

In each run, the order of HashMap is different (as expected). For example:

Output #1:

b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 
b3, b4, b7, b9, b0, b8, b1, b2, b6, b5,

Output #2:

b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 
b9, b4, b3, b7, b8, b0, b1, b5, b6, b2,

But the strange thing is that if I replace the lines

t.start();
t.join();

with

t.run();

(not using multithreading) the output is always the same:

b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 
b0, b3, b7, b4, b2, b6, b9, b1, b5, b8, 

I don't understand the relationship between HashMap's order and Thread. Can someone please explain to me why is this happening?

like image 736
Mehran Mirkhan Avatar asked Mar 27 '18 07:03

Mehran Mirkhan


People also ask

Why order is not maintained in HashMap?

” HashMap does not preserve insertion order “. HashMap is collection of Key and Value but HashMap does not give guaranty that insertion order will preserve. i.e here we are adding data of student result from 1st to 3rd year but when we retrieve its there are possibility to change sequence.

Does HashMap retain order?

HashMap does not maintains insertion order in java. Hashtable does not maintains insertion order in java. LinkedHashMap maintains insertion order in java. TreeMap is sorted by natural order of keys in java.

Does HashMap guarantee default ordering?

toMap returns a new HashMap, but as we know, HashMap doesn't guarantee iteration order, while LinkedHashMap does.

Do HashMaps automatically sort?

No, HashMap s don't sort their keys automatically. You want a TreeMap for sorting the keys, or a LinkedHashMap to retain the insertion order.


1 Answers

It's because HashMap order internally will depend on hashcode implementation.

Your Book class does not implement hashCode so it will use the default one

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

That means it will use memory address.

In your case, it happens that for a single thread, allocated memory addresses are the same on re-run, which is not the case in threaded version.

But this is only 'by accident' and you cannot rely on it even in single threaded (someone else will run it and get a different result, or even when you run it later you can get a different result as objects will have different memory addresses)

Please ALWAYS overwrite hashCode (&equals) when using objects in hashmap.

like image 115
Maciej Avatar answered Oct 03 '22 21:10

Maciej