我們平時寫程序需要經常用到集合類,比如ArrayList、HashMap等,但是這些集合不能夠實現併發運行機制,這樣在服務器上運行時就會非常的消耗資源和浪費時間,並且對這些集合進行迭代的過程中不能進行操作,否則會出現錯誤,例如下面程序:
- public class CollectionModifyExceptionTest {
- public static void main(String[] args) {
- Collection users = new ArrayList();
- users.add(new User("張三",28));
- users.add(new User("李四",25));
- users.add(new User("王五",31));
- Iterator itrUsers = users.iterator();
- while(itrUsers.hasNext()){
- System.out.println("正在執行!");
- User user = (User)itrUsers.next();
- if("李四".equals(user.getName())){
- users.remove(user);
- } else {
- System.out.println(user);
- }
- }
- }
- }
併發集合類主要有:
ConcurrentHashMap; ConcurrentSkipListMap; ConCurrentSkipListSet; CopyOnWriteArrayList; CopyOnWriteArraySet; ConcurrentLinkedQueue;
下面其中的某些集合類進行分別簡述:
ConcurrentHashMap支持完全併發的檢索和更新所希望的可調整併發的哈希表。此類遵守與 Hashtable 相同的功能規範,並且包括對應於 Hashtable 的每個方法的方法版本。不過,儘管所有操作都是線程安全的,但檢索操作不 必鎖定,並且不 支持以某種防止所有訪問的方式鎖定整個表。此類可以通過程序完全與 Hashtable 進行互操作,這取決於其線程安全,而與其同步細節無關。
主要構造方法有:
- ConcurrentHashMap(); //創建一個帶有默認初始容量、加載因子和 concurrencyLevel 的新的空映射。
- ConcurrentHashMap(int initialCapacity); //創建一個帶有指定初始容量、默認加載因子和 concurrencyLevel 的新的空映射。
- ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel); //創建一個帶有指定初始容量、加載因子和併發級別的新的空映射。
- ConcurrentHashMap(Map<> t); //構造一個與給定映射具有相同映射關係的新映射。
主要構造方法有:
- ConcurrentLinkedQueue(); //創建一個最初爲空的 ConcurrentLinkedQueue。
- ConcurrentLinkedQueue(Collection<> c);// 創建一個最初包含給定 collection 的元素的 ConcurrentLinkedQueue,按照此 collection 迭代器的遍歷順序來添加元素
CopyOnWriteArrayList是ArrayList 的一個線程安全的變形,其中所有可變操作(添加、設置,等等)都是通過對基礎數組進行一次新的複製來實現的。這一般需要很大的開銷,但是當遍歷操作的數量大大超過可變操作的數量時,這種方法可能比其他替代方法更 有效。在不能或不想進行同步遍歷,但又需要從併發線程中排除衝突時,它也很有用。“快照”風格的迭代器方法在創建迭代器時使用了對數組狀態的引用。此數組在迭代器的生存期內絕不會更改,因此不可能發生衝突,並且迭代器保證不會拋出 ConcurrentModificationException。自創建迭代器以後,迭代器就不會反映列表的添加、移除或者更改。不支持迭代器上更改元素的操作(移除、設置和添加)。這些方法將拋出 UnsupportedOperationException。
主要構造方法有:
- CopyOnWriteArrayList(); // 創建一個空列表。
- CopyOnWriteArrayList(Collection<> c); //按照 Collection 的迭代器返回元素的順序,創建一個包含指定 Collection 的元素的列表。
- CopyOnWriteArrayList(E[] toCopyIn); //創建一個新的 CopyOnWriteArrayList,它保持給定數組的副本。
- 它最適合於 set 大小通常保持很小、只讀操作遠多於可變操作以及需要在遍歷期間防止線程間衝突的應用程序。
- 它是線程安全的。
- 因爲通常需要複製整個基礎數組,所以可變操作(添加、設置、移除,等等)的開銷巨大。
- 迭代器不支持可變移除操作。
- 使用迭代器進行遍歷的速度很快,並且不會與其他線程發生衝突。在構造迭代器時,迭代器依賴於不變的數組快照。
- CopyOnWriteArraySet(); //創建一個空 set
- CopyOnWriteArraySet(Collection<> c); //創建一個包含指定 Collection 中所有元素的 set
講完併發集合類以後再回到本文剛開始的例子中,如果將Collection users = new ArrayList();改寫成Collection users = new CopyOnWriteArrayList();再運行程序,程序就會正常進行了,結果如下:
- 正在執行!
- {name:'張三',age:28}
- 正在執行!
- 正在執行!
- {name:'王五',age:31}