Java之currenHashMap
? ? ? ? currenHashMap是jkd1.5引入的,其特點是:效率比Hashtable高,并發性比HashMap好。結合了兩者的特點。
??????? ConcurrentHashMap是一個線程安全的Hash Table,它的主要功能是提供了一組和HashTable功能相同但是線程安全的方法。ConcurrentHashMap可以做到讀取數據不加鎖,并且其內部的結構可以讓其在進行寫操作的時候能夠將鎖的粒度保持地盡量地小,不用對整個ConcurrentHashMap加鎖。
??????? ConcurrentHashMap為了提高本身的并發能力,在內部采用了一個叫做Segment的結構,一個Segment其實就是一個類Hash Table的結構,Segment內部維護了一個鏈表數組,我們用下面這一幅圖來看下ConcurrentHashMap的內部結構:
??????? 從上面的結構我們可以了解到,ConcurrentHashMap定位一個元素的過程需要進行兩次Hash操作,第一次Hash定位到Segment,第二次Hash定位到元素所在的鏈表的頭部,因此,這一種結構的帶來的副作用是Hash的過程要比普通的HashMap要長,但是帶來的好處是寫操作的時候可以只對元素所在的Segment進行加鎖即可,不會影響到其他的Segment,這樣,在最理想的情況下,ConcurrentHashMap可以最高同時支持Segment數量大小的寫操作(剛好這些寫操作都非常平均地分布在所有的Segment上),所以,通過這一種結構,ConcurrentHashMap的并發能力可以大大的提高。
??????? HashMap中未進行同步考慮,而Hashtable則使用了synchronized,帶來的直接影響就是可選擇,我們可以在單線程時使用HashMap提高效率,而多線程時用Hashtable來保證安全。通過分析Hashtable就知道,synchronized是針對整張Hash表的,即每次鎖住整張表讓線程獨占,安全的背后是巨大的浪費。
?
??????? 左邊便是Hashtable的實現方式---鎖整個hash表;而右邊則是ConcurrentHashMap的實現方式---段鎖。它使用了多個鎖來控制對hash表的不同部分進行的修改。?ConcurrentHashMap將hash表分為16段(默認值),諸如get,put,remove等常用操作只鎖當前需要用到的段。試想,原來 只能一個線程進入,現在卻能同時16個寫線程進入(寫線程才需要鎖定,而讀線程幾乎不受限制,之后會提到),并發性的提升是顯而易見的。
?? ? ? ? ConcurrentHashMap的讀取并發,因為在讀取的大多數時候都沒有用到鎖定,所以讀取操作幾乎是完全的并發操作,而寫操作鎖定的粒度又非常細,比起之前又更加快速(這一點在桶更多時表現得更明顯些)。只有在求size()和containsValue()等操作時才需要鎖定整個表。它們可能需要鎖定整個 表而而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢后,又按順序釋放所有段的鎖(防止死鎖)。
??????? 讀是否要加鎖,因為讀寫會發生沖突?ConcurrentHashMap完全允許多個讀操作并發進行,讀操作并不需要加鎖。如果使 用傳統的技術,如HashMap中的實現,如果允許可以在hash鏈的中間添加或刪除元素,讀操作不加鎖將得到不一致的數據。 ConcurrentHashMap實現技術是保證HashEntry幾乎是不可變的。HashEntry代表每個hash鏈中的一個節點,其結構如下所 示:
static final class HashEntry<K,V> {final K key;
final int hash;
volatile V value;
final HashEntry<K,V> next;
}
? ? ? 可以看到HashEntry的一個特點,除了value以外,其他的幾個變量都是final的,這樣做是為了防止鏈表結構被破壞,出現ConcurrentModification的情況。為了確保讀操作能夠看到最新的值,將value設置成volatile,這避免了加鎖。在當前的Java內存模型下,線程可以把變量保存在本地內存(比如機器的寄存器)中,而不是直接在主存中進行讀寫。這就可能造成一個線程在主存中修改了一個變量的值,而另外一個線程還繼續使用它在寄存器中的變量值的拷貝,造成數據的不一致。volatile關鍵字指示JVM,這個變量是不穩定的,每次使用它都到主存中進行讀取。一般說來,多任務環境下各任務間共享的標志都應該加volatile修飾。Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。
--------------------------------------------------------------------
PS:?歡迎關注公眾號"Devin說",會不定期更新Java相關技術知識。
--------------------------------------------------------------------
其他請參考:http://www.cnblogs.com/maxupeng/archive/2011/06/26/2090517.html
轉載于:https://www.cnblogs.com/devinzhang/archive/2012/02/24/2366678.html
總結
以上是生活随笔為你收集整理的Java之currenHashMap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我国农业科学需要在哪些方面研发?
- 下一篇: 本人98年户籍由湖南当地农村转入学校,0