[Java並發編程] 並發容器框架的簡單介紹
三軍可奪帥也,匹夫不可奪誌也。———《論語》
上一篇講到同步容器類的潛在問題,可以通過兩個方法解決。
可以通過客戶端加鎖解決。
可以使用並發容器類來解決問題。
客戶端加鎖的方法我們已經知道,所以,這一篇介紹一下並發容器類原理,看它是如何解決這些問題的。
下面看下並發容器的框架圖:
我們從上圖可以看到,它們分為五大類:Map, List, Set,Collection,Queue, 同步容器類都是從這五大基類繼承而來,它們都是線程安全的。
同步容器類實現線程安全性的方式是所有方法都持有一個鎖,並發容器則不同,這裏主要講介紹幾個並發容器類來說明。
ConcurrentHashMap
它並不是每個方法都在同一個鎖上實現同步使得每次只能有一個線程訪問容器。而是使用一種粒度更細的加鎖機制來實現更大程度的共享,這種機制稱為分段鎖
由於 ConcurrentHashMap 不能加鎖來執行獨占訪問,因此我們無法通過客戶端加鎖來創建新的原子操作。然而,一些常見的復合操作已經實現了。包括如下接口:
這裏寫圖片描述當你需要這些額外的原子操作時,那麽你可以考慮使用它。
CopyOnWriteArrayList
寫時復制容器,可以理解為向容器添加一個元素時,先將當前的容器進行復制,生成一個新的容器,然後在向新的容器添加元素,之後再將原容器的引用指向新的容器
好處是,對 CopyOnWrite 容器可以不用加鎖進行並發的讀,因為此時不會添加任何元素。CopyOnWrite 是一種讀寫分離的思想,讀操作和寫操作的是不同的容器。
它可以用於替代同步 List,但是每次在修改容器時都會復制底層數組。比如 add(),set() 等操作時,需要一定的開銷,特別是當容器規模較大時,它比較適用於讀多寫少的並發場景。
ArrayBlockingQueue
它是數組實現的線程安全的有界的阻塞隊列(FIFO),支持多任務並發操作。它內部通過互斥鎖保護競爭資源,實現了多線程對競爭資源的互斥訪問;有界是指數組的長度是固定的;阻塞是指當競爭資源已經某線程獲取時,其他要獲取該資源的線程需要阻塞等待。
它的核心函數都是通過可重入鎖 ReentrantLock 來確保線程同步的。包括 put(),offer(),take(),poll() 等。同時,還包含兩個條件 Condition(notEmpty, notFull),加入元素是,如果隊列已滿則必須等待;取出元素時,如果隊列為空則必須等待。
總結
並發容器是針對多個線程並發訪問設計的,通過並發容器來代替同步容器,可以極大的提高伸縮性並降低風險。並發容器提供的叠代不會拋出 ConcurrentModificationException,因此在叠代過程中不需要對容器加鎖。另外,並發容器只能保證數據的最終一致性,不能保證實時一致性。換句話說,容器被修改後的數據並不保證能夠實時的反應到叠代器的遍歷。
參考
《Java並發編程實戰》
http://www.cnblogs.com/leesf456/p/5428630.html
[Java並發編程] 並發容器框架的簡單介紹