java併發:同步容器&併發容器

第一節 同步容器、併發容器html

1.簡述同步容器與併發容器java

  在Java併發編程中,常常聽到同步容器、併發容器之說,那什麼是同步容器與併發容器呢?同步容器能夠簡單地理解爲經過synchronized來實現同步的容器,好比Vector、Hashtable以及SynchronizedList等容器,若是有多個線程調用同步容器的方法,它們將會串行執行。程序員

  能夠經過查看Vector、Hashtable等同步容器的實現代碼,能夠看到這些容器實現線程安全的方式就是將它們的狀態封裝起來,並在須要同步的方法上加上關鍵字synchronized,但在某些狀況下,同步容器不必定就是線程安全的,好比獲取最後一個元素或者刪除最後一個元素,咱們須要實現額外的同步操做:編程

public static Object getLast(Vector list) {  
    int lastIndex = list.size() - 1;  
    return list.get(lastIndex);  
}  
      
public static void deleteLast(Vector list) {  
    int lastIndex = list.size() - 1;  
    list.remove(lastIndex);  
} 

  雖然上面的方法看起來沒有問題,Vector自身的方法也是同步的,可是在多線程環境中仍是隱藏着問題。若是有兩個線程A,B同時調用上面的兩個方法,假設list的大小爲10,這裏計算獲得的lastIndex爲9,線程B首先執行了刪除操做(多線程之間操做執行的不肯定性致使),然後線程A調用了list.get方法,這時就會發生數組越界異常,致使問題的緣由就是上面的複合操做不是原子操做,這裏能夠經過在方法內部使用list對象鎖來實現原子操做。數組

  同步容器會致使多個線程中對容器方法調用的串行執行,下降併發性,由於它們都是以容器自身對象爲鎖,因此在須要支持併發的環境中,能夠考慮使用併發容器來替代。安全

  併發容器是針對多個線程併發訪問而設計的,在jdk5.0引入了concurrent包,其中提供了不少併發容器,如ConcurrentHashMap、CopyOnWriteArrayList等。網絡

  其實同步容器與併發容器都爲多線程併發訪問提供了合適的線程安全,不過併發容器的可擴展性更高。在Java5以前,程序員們只有同步容器,且在多線程併發訪問的時候會致使爭用,阻礙了系統的擴展性。Java5介紹了併發容器,併發容器使用了與同步容器徹底不一樣的加鎖策略來提供更高的併發性和伸縮性,例如,在ConcurrentHashMap中採用了一種粒度更細的加鎖機制,能夠稱爲分段鎖,在這種鎖機制下,容許任意數量的讀線程併發地訪問map,而且執行讀操做的線程和寫操做的線程也能夠併發的訪問map,同時容許必定數量的寫操做線程併發地修改map,因此它能夠在併發環境下實現更高的吞吐量,另外,併發容器提供了一些在使用同步容器時須要本身實現的複合操做,包括putIfAbsent等,可是因爲併發容器不能經過加鎖來獨佔訪問,因此咱們沒法經過加鎖來實現其餘複合操做了。多線程

 

2.參考資料:併發

(1)http://www.cnblogs.com/dolphin0520/p/3933404.html函數

 

第二節 ConcurrentHashMap

1.初識ConcurrentHashMap

針對併發容器中的ConcurrentHashMap,《java併發編程實戰》一書有以下這樣一段文字:

此處將揭開ConcurrentHashMap的神祕面紗,首先咱們看一下ConcurrentHashMap的結構圖,以下:

 

2.詳述ConcurrentHashMap

(1)ConcurrentHashMap的併發度

  ConcurrentHashMap把實際map劃分紅若干部分來實現它的可擴展性和線程安全。這種劃分是使用併發度得到的,它是ConcurrentHashMap類構造函數的一個可選參數,默認值爲16,這樣在多線程狀況下就能避免爭用。

 

(2)ConcurrentHashMap的鎖分離技術

  HashTable容器在競爭激烈的併發環境下效率低下,緣由是全部訪問HashTable的線程都必須競爭同一把鎖。若容器中有多把鎖,每一把鎖用於鎖定容器其中一部分數據,那麼當多線程訪問容器裏不一樣數據段的數據時,線程間就不會存在鎖競爭,從而能夠有效提升併發訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術,首先將數據分紅一段一段的存儲,而後給每一段數據配一把鎖,當一個線程佔用鎖並訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問。

   對比上圖(該圖摘自網絡),同步容器HashTable實現鎖的方式是鎖整個hash表,而併發容器ConcurrentHashMap的實現方式是鎖桶(簡單理解就是將整個hash表想象成一大缸水,如今將這大缸裏的水分到了幾個水桶裏,hashTable每次都鎖定這個大缸,而ConcurrentHashMap則每次只鎖定其中一個 桶)。

    ConcurrentHashMap將hash表分爲16個桶(默認值),諸如get,put,remove等經常使用操做只鎖當前須要用到的桶。試想,原來只能一個線程進入,如今卻能同時16個線程進入,併發性的提高是顯而易見的。

 

(3)ConcurrentHashMap的remove操做

當對ConcurrentHashMap進行remove操做時,並非進行簡單的節點刪除操做

  對比上圖,當對ConcurrentHashMap的一個segment(也就是一個桶中的節點)進行remove後,例如,刪除節點C,C節點實際並無被銷燬,而是將C節點前面的反轉並拷貝到新的鏈表中,C節點後面的不須要被克隆。這樣的操做使併發的讀線程不受併發的寫線程的干擾,例如,如今有一個讀線程讀到了A節點,寫線程把C刪掉了,可是看上圖,讀線程仍然能夠繼續讀下去;固然,若是在刪除C以前讀線程讀到的是D,那麼更不會有影響。

    根據上面所提到的在ConcurrentHashMap中刪除一個節點並不會馬上被讀線程感覺到的效果,就是傳說中的弱一致性,因此ConcurrentHashMap的迭代器是弱一致性迭代器

 

3.參考資料:

本小節僅簡單概述了ConcurrentHashMap的一些內容,其實現機制等可參考如下優質文章

(1)http://www.cnblogs.com/ITtangtang/p/3948786.html

(2)http://ifeve.com/concurrenthashmap/

(3)http://blog.csdn.net/xuefeng0707/article/details/40834595

相關文章
相關標籤/搜索