java併發包學習系列:jdk併發容器

下一個五年發表於2016-07-13

同步容器

同步容器可以簡單地理解為通過synchronized來實現同步的容器,如果有多個執行緒呼叫同步容器的方法,它們將會序列執行。

同步容器將它們的狀態封裝起來,並對每一個公有方法進行同步。主要包括:

  • Vector
  • Stack
  • HashTable
  • Collections.synchronized方法生成,例如:
    Collectinons.synchronizedList()
    Collections.synchronizedSet()
    Collections.synchronizedMap()
    Collections.synchronizedSortedSet()
    Collections.synchronizedSortedMap()
    其中Vector(同步的ArrayList)和Stack(繼承自Vector,先進後出)、HashTable(繼承自Dictionary,實現了Map介面)是比較老的容器,Thinking in Java中明確指出,這些容器現在仍然存在於JDK中是為了向以前老版本的程式相容,在新的程式中不應該在使用。Collections的方法時將非同步的容器包裹生成對應的同步容器。

同步容器在單執行緒的環境下能夠保證執行緒安全,但是通過synchronized同步方法將訪問操作序列化,導致併發環境下效率低下。而且同步容器在多執行緒環境下的複合操作(迭代、條件運算如沒有則新增等)是非執行緒安全,需要客戶端程式碼來實現加鎖。

併發容器

由上面的分析我們知道,同步容器並不能保證多執行緒安全,而併發容器是針對多個執行緒併發訪問而設計的,在jdk5.0引入了concurrent包,其中提供了很多併發容器,極大的提升同步容器類的效能。

ConcurrentHashMap

對應的非併發容器:HashMap
目標:代替Hashtable、synchronizedMap,支援複合操作
原理:JDK6中採用一種更加細粒度的加鎖機制Segment“分段鎖”,JDK8中採用CAS無鎖演算法

CopyOnWriteArrayList

對應的非併發容器:ArrayList
目標:代替Vector、synchronizedList
原理:利用高併發往往是讀多寫少的特性,對讀操作不加鎖,對寫操作,先複製一份新的集合,在新的集合上面修改,然後將新集合賦值給舊的引用,並通過volatile 保證其可見性,當然寫操作的鎖是必不可少的了。

CopyOnWriteArraySet

對應的費併發容器:HashSet
目標:代替synchronizedSet
原理:基於CopyOnWriteArrayList實現,其唯一的不同是在add時呼叫的是CopyOnWriteArrayList的addIfAbsent方法,其遍歷當前Object陣列,如Object陣列中已有了當前元素,則直接返回,如果沒有則放入Object陣列的尾部,並返回。

ConcurrentSkipListMap

對應的非併發容器:TreeMap
目標:代替synchronizedSortedMap(TreeMap)
原理:Skip list(跳錶)是一種可以代替平衡樹的資料結構,預設是按照Key值升序的。Skip list讓已排序的資料分佈在多層連結串列中,以0-1隨機數決定一個資料的向上攀升與否,通過”空間來換取時間”的一個演算法。ConcurrentSkipListMap提供了一種執行緒安全的併發訪問的排序對映表。內部是SkipList(跳錶)結構實現,在理論上能夠在O(log(n))時間內完成查詢、插入、刪除操作。

ConcurrentSkipListSet

對應的非併發容器:TreeSet
目標:代替synchronizedSortedSet
原理:內部基於ConcurrentSkipListMap實現

ConcurrentLinkedQueue

不會阻塞的佇列

對應的非併發容器:Queue
原理:基於連結串列實現的FIFO佇列(LinkedList的併發版本)

BlockingQueue:資料共享通道

比如,執行緒A希望執行緒B發一個訊息,用什麼方式告知執行緒B比較合理的呢?用BlockingQueue最為合理。

BlockingQueue是一個介面,並非一個具體的實現。
BlockingQueue之所以適合做資料共享的通道,其關鍵還在於Blocking上。Blocking是阻塞的意思,當服務執行緒(服務執行緒指不斷獲取佇列中的訊息,進行處理的執行緒)處理完成佇列中的訊息後,他如何得知下一條訊息何時到來呢?一種傻瓜式的方案是讓這個執行緒按照一定的時間間隔不停的迴圈和監控這個佇列。這是可行的一種方案,但顯然造成了不必要的資源浪費,而迴圈週期也難以確定。而BlockingQueue很好的解決了這一個問題。它會讓服務執行緒在佇列為空是時,進行等待,當有新的訊息進入佇列後,自動將執行緒喚醒。

特點:擴充了Queue,增加了可阻塞的插入和獲取等操作
原理:通過ReentrantLock實現執行緒安全,通過Condition實現阻塞和喚醒
實現類:
LinkedBlockingQueue:基於連結串列實現的可阻塞的FIFO佇列
ArrayBlockingQueue:基於陣列實現的可阻塞的FIFO佇列
PriorityBlockingQueue:按優先順序排序的佇列

相關文章