併發集合類 ConcurrentHashMap 和 CopyOnWriteArrayList

     在Java類庫中出現的第一個關聯的集合類是 Hashtable ,它是JDK 1.0的一部分。 Hashtable 提供了一種易於使用的、線程安全的、關聯的map功能,這當然也是方便的。然而,線程安全性是憑代價換來的―― Hashtable 的所有方法都是同步的。此時,無競爭的同步會導致可觀的性能代價。 Hashtable 的後繼者 HashMap 是作爲JDK1.2中的集合框架的一部分出現的,它通過提供一個不同步的基類和一個同步的包裝器 Collections.synchronizedMap ,解決了線程安全性問題。通過將基本的功能從線程安全性中分離開來, Collections.synchronizedMap 允許需要同步的用戶可以擁有同步,而不需要同步的用戶則不必爲同步付出代價。 Hashtable 和 synchronizedMap 所採取的獲得同步的簡單方法(同步 Hashtable 中或者同步的 Map 包裝器對象中的每個方法)有兩個主要的不足。首先,這種方法對於可伸縮性是一種障礙,因爲一次只能有一個線程可以訪問hash表。同時,這樣仍不足以提供真正的線程安全性,許多公用的混合操作仍然需要額外的同步。雖然諸如 get() 和 put() 之類的簡單操作可以在不需要額外同步的情況下安全地完成,但還是有一些公用的操作序列,例如迭代或者put-if-absent(空則放入),需要外部的同步,以避免數據爭用。 有條件的線程安全性 同步的集合包裝器 synchronizedMap 和 synchronizedList ,有時也被稱作 有條件地線程安全――所有單個的操作都是線程安全的,但是多個操作組成的操作序列卻可能導致數據爭用,因爲在操作序列中控制流取決於前面操作的結果。

      清單1中第一片段展示了公用的put-if-absent語句塊――如果一個條目不在 Map 中,那麼添加這個條目。不幸的是,在 containsKey() 方法返回到 put() 方法被調用這段時間內,可能會有另一個線程也插入一個帶有相同鍵的值。如果您想確保只有一次插入,您需要用一個對 Map m 進行同步的同步塊將這一對語句包裝起來。 清單1中其他的例子與迭代有關。在第一個例子中, List.size() 的結果在循環的執行期間可能會變得無效,因爲另一個線程可以從這個列表中刪除條目。如果時機不得當,在剛好進入循環的最後一次迭代之後有一個條目被另一個線程刪除了,則 List.get() 將返回 null ,而 doSomething() 則很可能會拋出一個 NullPointerException 異常。那麼,採取什麼措施才能避免這種情況呢?如果當您正在迭代一個 List 時另一個線程也可能正在訪問這個 List ,那麼在進行迭代時您必須使用一個 synchronized 塊將這個 List 包裝起來,在 List 1 上同步,從而鎖住整個 List 。這樣做雖然解決了數據爭用問題,但是在併發性方面付出了更多的代價,因爲在迭代期間鎖住整個 List 會阻塞其他線程,使它們在很長一段時間內不能訪問這個列表。 集合框架引入了迭代器,用於遍歷一個列表或者其他集合,從而優化了對一個集合中的元素進行迭代的過程。然而,在 java.util 集合類中實現的迭代器極易崩潰,也就是說,如果在一個線程正在通過一個 Iterator 遍歷集合時,另一個線程也來修改這個集合,那麼接下來的 Iterator.hasNext() 或 Iterator.next() 調用將拋出 ConcurrentModificationException 異常。就拿剛纔這個例子來講,如果想要防止出現 ConcurrentModificationException 異常,那麼當您正在進行迭代時,您必須使用一個在 List l 上同步的 synchronized 塊將該 List 包裝起來,從而鎖住整個 List 。(或者,您也可以調用 List.toArray() ,在不同步的情況下對數組進行迭代,但是如果列表比較大的話這樣做代價很高)。 清單 1. 同步的map中的公用競爭條件 Map m = Collections.synchronizedMap(new HashMap()); List l = Collections.synchronizedList(new ArrayList()); // put-if-absent idiom -- contains a race condition // may require external synchronization if (!map.containsKey(key)) map.put(key, value); // ad-hoc iteration -- contains race conditions // may require external synchronization for (int i=0; i

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章