Java之currenHashMap

來源:互聯網
上載者:User

        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修飾的成員變數在每次被線程訪問時,都強迫從共用記憶體中重讀該成員變數的值。而且,當成員變數發生變化時,強迫線程將變化值回寫到共用記憶體。這樣在任何時刻,兩個不同的線程總是看到某個成員變數的同一個值。

其他請參考:http://www.cnblogs.com/maxupeng/archive/2011/06/26/2090517.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.