網頁

2018/12/15

Java Hashtable與HashMap的區別

Java的HashtableHashMap的區別如下。

  1. Hashtable不能以null為key;HashMap可以null為key。
  2. Hashtable是執行緒安全的;HashMap是非執行緒安全的。
  3. Hashtable效能比HashMap差。因為Hashtable為執行緒安全,也就是synchronized的,所以在單執行緒時的效能比非執行緒安全的HashMap差。

第1點Hashtable不能以null為key的範例如下

HashMap<String, String> hm = new HashMap<>();
hm.put(null, "1"); // OK

Hashtable<String, String> ht = new Hashtable<>();
ht.put(null, "1"); // 丟出NullPointerException

關於第二點,對非執行緒安全的HashMap併行修改(concurrent modification)資料,會發生ConcurrentModificationException例外,例如執行下面程式時,因為不同的執行緒修改了HashMap<String, String> hm,所以可能發生錯誤。

HashMap<String, String> hm = new HashMap<>();

for (int i = 0; i < 1000; i++) {
    hm.put("key" + i, "value" + i);
}

// 執行緒1, 遍歷印出每個key-value值
Thread t1 = new Thread(() -> {
    Iterator<Map.Entry<String, String>> it = hm.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, String> entry = it.next();
        System.out.println(entry.getKey() + ":" + entry.getValue());
    }
});

// 執行緒2, 增加一個key-value
Thread t2 = new Thread(() -> {
    hm.put("key1000", "value1000");
});

t1.start();
t2.start();

錯誤訊息如下

Exception in thread "Thread-0" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
    at java.util.HashMap$EntryIterator.next(HashMap.java:1476)
    at java.util.HashMap$EntryIterator.next(HashMap.java:1474)
    at idv.matt.demo.Main.lambda$0(Main.java:25)
    at java.lang.Thread.run(Thread.java:748)

不過如果要對Map資料進行多執行續操作,建議使用ConcurrentHashMap,因為效能優於Hashtable


參考:

2 則留言:

  1. Hi 想請問如果我將
    `HashMap hm = new HashMap<>();`
    改成
    `HashTable hm = new HashTable<>();` 或
    ` final Map hm = Collections.synchronizedMap(new HashMap<>());
    `
    執行這段程式還是會出現ConcurrentModificationException, 跟我想像的不太一樣,請問是哪裡的觀念還需要注意嗎? 謝謝

    回覆刪除
  2. 小丸您好,我試了
    Hashtable hm = new Hashtable<>(); 或
    ConcurrentHashMap hm = new ConcurrentHashMap();
    都沒出現ConcurrentModificationException,可能要再請您試試看。

    回覆刪除