1. 程式人生 > 其它 >同樣是執行緒安全,ConcurrentHashMap 和 Hashtable 的區別?

同樣是執行緒安全,ConcurrentHashMap 和 Hashtable 的區別?

我們都知道 HashMap 不是執行緒安全的,而 ConcurrentHashMap 和 Hashtable 它們兩個確實都是執行緒安全的,那它們有哪些不同點呢?

出現的版本不同

Hashtable 在 JDK1.0 的時候就存在了,並在 JDK1.2 版本中實現了 Map 介面,成為了集合框架的一員。

而 ConcurrentHashMap 則是在 JDK1.5 中才出現的。

實現執行緒安全的方式不同

Hashtable 實現併發安全的原理是通過 synchronized 關鍵字,讓我們直接看下原始碼,以 put() 方法為例,程式碼如下:

可以看出這個put() 方法是被 synchronized 關鍵字所修飾的,同理其他的方法例如 clear、get、size 等,也同樣是被 synchronized 關鍵字修飾的。之所以 Hashtable 是執行緒安全的,是因為幾乎每個方法都被 synchronized 關鍵字所修飾了,這也就保證了執行緒安全

Collections.SynchronizedMap(new HashMap()) 的原理和 Hashtable 類似,也是利用 synchronized 實現的。而我們的 ConcurrentHashMap 實現的原理,卻有大大的不同,本質上它實現執行緒安全的原理是利用了 CAS + synchronized + Node 節點的方式,這和 Hashtable 的完全利用 synchronized 的方式有很大的不同。

ConcurrentHashMap的詳細介紹請看我的另一篇文章——— ConcurrentHashMap 在 Java7 和 8 有何不同

效能不同

正因為它們線上程安全的實現方式上的不同,導致它們在效能方面也有很大的不同。當執行緒數量增加的時候,Hashtable 的效能會急劇下降,因為每一次修改都需要鎖住整個物件,而其他執行緒在此期間是不能操作的。不僅如此,還會帶來額外的上下文切換等開銷

,所以此時它的吞吐量甚至還不如單執行緒的情況。

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

迭代時修改的不同

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

可以看出在這個 next() 方法中,會首先判斷 modCount 是否等於 expectedModCount。其中 expectedModCount 是在迭代器生成的時候隨之生成的,並且不會改變。它所代表的含義是當前 Hashtable 被修改的次數,而每一次去呼叫 Hashtable 的包括 addEntry()、remove()、rehash() 等方法中,都會修改 modCount 的值。這樣一來,如果我們在迭代的過程中,去對整個 Hashtable 的內容做了修改的話,也就同樣會反映到 modCount 中。這樣一來,迭代器在進行 next 的時候,也可以感知到,於是它就會發現 modCount 不等於 expectedModCount,就會丟擲 ConcurrentModificationException 異常。

所以對於 Hashtable 而言,它是不允許在迭代期間對內容進行修改的。相反,ConcurrentHashMap 即便在迭代期間修改內容,也不會丟擲ConcurrentModificationException

希望本文章對您有幫助,您的轉發、點贊是我的創作動力,十分感謝。更多好文推薦,請關注我的微信公眾號--JustJavaIt