同樣是線程安全,ConcurrentHashMap 和 Hashtable 區別?

同樣是線程安全,ConcurrentHashMap 和 Hashtable 區別?

前言

通過之前的文章《HashMap 爲什麼線程不安全?》,我們都知道 HashMap 不是線程安全的,而本章中 ConcurrentHashMap 和 Hashtable 它們兩個都是線程安全的,那它們有哪些不同點呢?我們從以下四個角度出發,去分析它們的不同點。

1.出現的版本不同

我們先從表面的、顯而易見的出現時間來分析。Hashtable 在 JDK1.0 的時候就存在了,並在 JDK1.2 版本中實現了 Map 接口,成爲了集合框架的一員。而 ConcurrentHashMap 則是在 JDK1.5 中才出現的,也正是因爲它們出現的年代不同,而後出現的往往是對前面出現的類的優化,所以它們在實現方式以及性能上,也存在着較大的不同。

2.實現線程安全的方式不同

Hashtable 實現併發安全的原理是通過 synchronized 關鍵字,Collections.SynchronizedMap(new HashMap()) 的原理和 Hashtable 類似,也是利用 synchronized 實現的。

hashtable 部分源碼如下:

    public synchronized V get(Object key) {...}
    public synchronized V put(K key, V value) {...}
    public synchronized V remove(Object key) {...}
    ...

ConcurrentHashMap 實現線程安全的原理是利用了 CAS + synchronized + Node 節點的方式,這和 Hashtable 的完全利用 synchronized 的方式有很大的不同。

3.性能不同

正因爲它們在線程安全的實現方式上的不同,導致它們在性能方面也有很大的不同。當線程數量增加的時候,Hashtable 的性能會急劇下降,因爲每一次修改都需要鎖住整個對象,而其他線程在此期間是不能操作的。不僅如此,還會帶來額外的上下文切換等開銷,所以此時它的吞吐量甚至還不如單線程的情況。

而在 ConcurrentHashMap 中,就算上鎖也僅僅會對一部分上鎖而不是全部都上鎖,所以多線程中的吞吐量通常都會大於單線程的情況,也就是說,在併發效率上,ConcurrentHashMap 比 Hashtable 提高了很多。

4.迭代時修改的不同

Hashtable(包括 HashMap)不允許在迭代期間修改內容,否則會拋出ConcurrentModificationException 異常,其原理是檢測 modCount 變量,迭代器的 next() 方法的代碼如下:

        public T next() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return nextElement();
        }

在遍歷元素的時候,會先判斷 modCount != expectedModCount,expectedModCount 表示當前 Hashtable 被修改的次數,這個值在迭代器生成的時候被賦值 protected int expectedModCount = modCount;,而每一次去調用 Hashtable 的包括 addEntry()、remove()、rehash() 等方法中,都會修改 modCount 的值。這樣一來,迭代器在進行 next 的時候,也可以感知到,於是它就會發現 modCount 不等於 expectedModCount,就會拋出 ConcurrentModificationException 異常。

相反,ConcurrentHashMap 即便在迭代期間修改內容,也不會拋出ConcurrentModificationException。

5.總結

本課時總結了 ConcurrentHashMap 與 Hashtable 的區別,雖然它們都是線程安全的,但是在出現的版本上、實現線程安全的方式上、性能上,以及迭代時是否支持修改等方面都有較大的不同,如果我們有併發的場景,那麼使用 ConcurrentHashMap 是最合適的,相反,Hashtable 已經不再推薦使用。

6.參考

  • 《Java 併發編程 78 講》- 徐隆曦
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章