Collections和Concurrent都是java用來輔助<? extends Set>和<? extends Collection>的工具類,旨在完成某些特殊而容易重複的任務 ,或者是一些比較那已解決的問題。在java中,經常使用的數據結構基本分爲3大類,Map,List,Set。
線程安全集合 JDK 1.2 中引入的 Collection 框架是一種表示對象集合的高度靈活的框架,它使用基本接口 List、Set 和 Map。經過 JDK 提供每一個集合的屢次實現(HashMap、Hashtable、TreeMap、WeakHashMap、HashSet、TreeSet、Vector、ArrayList、LinkedList 等等)。其中一些集合已是線程安全的(Hashtable 和 Vector),經過同步的封裝工廠(Collections.synchronizedMap()、synchronizedList() 和 synchronizedSet()),其他的集合都可表現爲線程安全的。 java.util.concurrent 包添加了多個新的線程安全集合類(ConcurrentHashMap、CopyOnWriteArrayList 和 CopyOnWriteArraySet)。這些類的目的是提供高性能、高度可伸縮性、線程安全的基本集合類型版本。 java.util 中的線程集合仍有一些缺點。例如,在迭代鎖定時,一般須要將該鎖定保留在集合中,不然,會有拋出 ConcurrentModificationException 的危險。(這個特性有時稱爲條件線程安全;有關的更多說明,請參閱參考資料。)此外,若是從多個線程頻繁地訪問集合,則經常不能很好地執行這些類。java.util.concurrent 中的新集合類容許經過在語義中的少許更改來得到更高的併發。 JDK 5.0 還提供了兩個新集合接口 -- Queue 和 BlockingQueue。Queue 接口與 List 相似,但它只容許從後面插入,從前面刪除。經過消除 List 的隨機訪問要求,能夠建立比現有 ArrayList 和 LinkedList 實現性能更好的 Queue 實現。由於 List 的許多應用程序實際上不須要隨機訪問,因此Queue 一般能夠替代 List,來得到更好的性能。
CopyOnWriteArrayList 和 CopyOnWriteArraySet 能夠用兩種方法建立線程安全支持數據的 List -- Vector 或封裝 ArrayList 和 Collections.synchronizedList()。java.util.concurrent 包添加了名稱繁瑣的 CopyOnWriteArrayList。爲何咱們想要新的線程安全的List類?爲何Vector還不夠? 最簡單的答案是與迭代和併發修改之間的交互有關。使用 Vector 或使用同步的 List 封裝器,返回的迭代器是 fail-fast 的,這意味着若是在迭代過程當中任何其餘線程修改 List,迭代可能失敗。 Vector 的很是廣泛的應用程序是存儲經過組件註冊的監聽器的列表。當發生適合的事件時,該組件將在監聽器的列表中迭代,調用每一個監聽器。爲了防止 ConcurrentModificationException,迭代線程必須複製列表或鎖定列表,以便進行總體迭代,而這兩種狀況都須要大量的性能成本。 CopyOnWriteArrayList 類經過每次添加或刪除元素時建立支持數組的新副本,避免了這個問題,可是進行中的迭代保持對建立迭代器時的當前副本進行操做。雖然複製也會有一些成本,可是在許多狀況下,迭代要比修改多得多,在這些狀況下,寫入時複製要比其餘備用方法具備更好的性能和併發性。 若是應用程序須要 Set 語義,而不是 List,那麼還有一個 Set 版本 -- CopyOnWriteArraySet。
ConcurrentHashMap 正如已經存在線程安全的 List 的實現,您能夠用多種方法建立線程安全的、基於 hash 的 Map -- Hashtable,並使用 Collections.synchronizedMap() 封裝 HashMap。JDK 5.0 添加了 ConcurrentHashMap 實現,該實現提供了相同的基本線程安全的 Map 功能,但它大大提升了併發性。 Hashtable 和 synchronizedMap 所採起的得到同步的簡單方法(同步 Hashtable 中或者同步的 Map 封裝器對象中的每一個方法)有兩個主要的不足。首先,這種方法對於可伸縮性是一種障礙,由於一次只能有一個線程能夠訪問 hash 表。同時,這樣仍不足以提供真正的線程安全性,許多公用的混合操做仍然須要額外的同步。雖然諸如 get() 和 put() 之類的簡單操做能夠在不須要額外同步的狀況下安全地完成,但仍是有一些公用的操做序列,例如迭代或者 put-if-absent(空則放入),須要外部的同步,以免數據爭用。 Hashtable 和 Collections.synchronizedMap 經過同步每一個方法得到線程安全。這意味着當一個線程執行一個 Map 方法時,不管其餘線程要對 Map 進行什麼樣操做,都不能執行,直到第一個線程結束才能夠。 對比來講,ConcurrentHashMap 容許多個讀取幾乎老是併發執行,讀和寫操做一般併發執行,多個同時寫入常常併發執行。結果是當多個線程須要訪問同一 Map 時,能夠得到更高的併發性。 在大多數狀況下,ConcurrentHashMap 是 Hashtable或 Collections.synchronizedMap(new HashMap()) 的簡單替換。然而,其中有一個顯著不一樣,即 ConcurrentHashMap 實例中的同步不鎖定映射進行獨佔使用。實際上,沒有辦法鎖定 ConcurrentHashMap 進行獨佔使用,它被設計用於進行併發訪問。爲了使集合不被鎖定進行獨佔使用,還提供了公用的混合操做的其餘(原子)方法,如 put-if-absent。ConcurrentHashMap 返回的迭代器是弱一致的,意味着它們將不拋出ConcurrentModificationException ,將進行"合理操做"來反映迭代過程當中其餘線程對 Map 的修改。
隊列 原始集合框架包含三個接口:List、Map 和 Set。List 描述了元素的有序集合,支持徹底隨即訪問 -- 能夠在任何位置添加、提取或刪除元素。 LinkedList 類常常用於存儲工做元素(等待執行的任務)的列表或隊列。然而,List 提供的靈活性比該公用應用程序所須要的多得多,這個應用程序一般在後面插入元素,從前面刪除元素。可是要支持完整 List 接口則意味着 LinkedList 對於這項任務不像原來那樣有效。Queue 接口比 List 簡單得多,僅包含 put() 和 take() 方法,並容許比 LinkedList 更有效的實現。 Queue 接口還容許實現來肯定存儲元素的順序。ConcurrentLinkedQueue 類實現先進先出(first-in-first-out,FIFO)隊列,而 PriorityQueue 類實現優先級隊列(也稱爲堆),它對於構建調度器很是有用,調度器必須按優先級或預期的執行時間執行任務。 interface Queue extends Collection { boolean offer(E x); E poll(); E remove() throws NoSuchElementException; E peek(); E element() throws NoSuchElementException; } 實現 Queue 的類是: • LinkedList 已經進行了改進來實現 Queue。 • PriorityQueue 非線程安全的優先級對列(堆)實現,根據天然順序或比較器返回元素。 • ConcurrentLinkedQueue 快速、線程安全的、無阻塞 FIFO 隊列。
Hashtable 與 ConcurrentHashMap 做爲可伸縮性的例子,ConcurrentHashMap 實現設計的可伸縮性要比其線程安全的上一代 Hashtable 的可伸縮性強得多。Hashtable 一次只容許一個線程訪問 Map;ConcurrentHashMap 容許多個讀者併發執行,讀者與寫入者併發執行,以及一些寫入者併發執行。所以,若是許多線程頻繁訪問共享映射,使用 ConcurrentHashMap 的總的吞吐量要比使用 Hashtable 的好。 下表大體說明了 Hashtable 和 ConcurrentHashMap 之間的可伸縮性差異。在每次運行時,N 個線程併發執行緊密循環,它們從 Hashtable 或 ConcurrentHashMap 中檢索隨即關鍵字,60% 的失敗檢索將執行 put() 操做,2% 的成功檢索執行 remove() 操做。測試在運行 Linux 的雙處理器 Xeon 系統中執行。數據顯示 10,000,000 個迭代的運行時間,對於 ConcurrentHashMap,標準化爲一個線程的狀況。能夠看到直到許多線程,ConcurrentHashMap 的性能仍保持可伸縮性,而 Hashtable 的性能在出現鎖定競爭時幾乎當即降低。 與一般的服務器應用程序相比,這個測試中的線程數看起來不多。然而,由於每一個線程未進行其餘操做,僅是重複地選擇使用該表,因此這樣能夠模擬在執行一些實際工做的狀況下使用該表的大量線程的競爭。
本文內容摘自:http://www.cnblogs.com/sarafill/archive/2011/05/18/2049461.htmlhtml
總結:具體來講,Vector,Hashtable在操做上是線程安全的,但在遍歷時線程並不安全,同理Collections.synchronizedMap()、synchronizedList() 和 synchronizedSet()雖然性能比前者有所提升,但遍歷時仍然須要和前者同樣加鎖才行。ConcurrentHashMap、CopyOnWriteArrayList 和 CopyOnWriteArraySet,ConcurrentLinkedQueue 性能和線程安全上有很大改進,遍歷時線程安全。java