Java線程(十四):Concurrent包中強大的併發集合類

       我們平時寫程序需要經常用到集合類,比如ArrayList、HashMap等,但是這些集合不能夠實現併發運行機制,這樣在服務器上運行時就會非常的消耗資源和浪費時間,並且對這些集合進行迭代的過程中不能進行操作,否則會出現錯誤,例如下面程序:

[java] view plaincopy
  1. public class CollectionModifyExceptionTest {  
  2.     public static void main(String[] args) {  
  3.         Collection users = new ArrayList();  
  4.         users.add(new User("張三",28));     
  5.         users.add(new User("李四",25));             
  6.         users.add(new User("王五",31));     
  7.         Iterator itrUsers = users.iterator();  
  8.         while(itrUsers.hasNext()){  
  9.             System.out.println("正在執行!");  
  10.             User user = (User)itrUsers.next();  
  11.             if("李四".equals(user.getName())){  
  12.                 users.remove(user);  
  13.             } else {  
  14.                 System.out.println(user);                 
  15.             }  
  16.         }  
  17.     }  
  18. }     
       程序在執行過程中會報錯, 因爲定義了一個ArrayList類型的集合,但是在對集合進行迭代的時候又出現了users.remove(user),即從集合從刪除數據,對於普通的集合來說這是不允許的,Java 5以後出現的併發集合類就是專門針對普通集合出現不能併發和不能在迭代過程中修改數據等問題而出現的。

      

 併發集合類主要有:

ConcurrentHashMap;          ConcurrentSkipListMap;              ConCurrentSkipListSet;           CopyOnWriteArrayList; CopyOnWriteArraySet;         ConcurrentLinkedQueue;


下面其中的某些集合類進行分別簡述:


 ConcurrentHashMap支持完全併發的檢索和更新所希望的可調整併發的哈希表。此類遵守與 Hashtable 相同的功能規範,並且包括對應於 Hashtable 的每個方法的方法版本。不過,儘管所有操作都是線程安全的,但檢索操作不 必鎖定,並且不 支持以某種防止所有訪問的方式鎖定整個表。此類可以通過程序完全與 Hashtable 進行互操作,這取決於其線程安全,而與其同步細節無關。

主要構造方法有:

[java] view plaincopy
  1. ConcurrentHashMap();  //創建一個帶有默認初始容量、加載因子和 concurrencyLevel 的新的空映射。  
  2. ConcurrentHashMap(int initialCapacity);   //創建一個帶有指定初始容量、默認加載因子和 concurrencyLevel 的新的空映射。  
  3. ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel);  //創建一個帶有指定初始容量、加載因子和併發級別的新的空映射。  
  4. ConcurrentHashMap(Map<> t);    //構造一個與給定映射具有相同映射關係的新映射。  


ConcurrentLinkedQueue是一個基於鏈接節點的、無界的、線程安全的隊列。此隊列按照 FIFO(先進先出)原則對元素進行排序,隊列的頭部 是隊列中時間最長的元素。隊列的尾部 是隊列中時間最短的元素。新的元素插入到隊列的尾部,隊列檢索操作從隊列頭部獲得元素。當許多線程共享訪問一個公共 collection 時,ConcurrentLinkedQueue 是一個恰當的選擇,此隊列不允許 null 元素。 

主要構造方法有:

[java] view plaincopy
  1. ConcurrentLinkedQueue();  //創建一個最初爲空的 ConcurrentLinkedQueue。  
  2. ConcurrentLinkedQueue(Collection<> c);// 創建一個最初包含給定 collection 的元素的 ConcurrentLinkedQueue,按照此 collection 迭代器的遍歷順序來添加元素  

CopyOnWriteArrayList是ArrayList 的一個線程安全的變形,其中所有可變操作(添加、設置,等等)都是通過對基礎數組進行一次新的複製來實現的。這一般需要很大的開銷,但是當遍歷操作的數量大大超過可變操作的數量時,這種方法可能比其他替代方法更 有效。在不能或不想進行同步遍歷,但又需要從併發線程中排除衝突時,它也很有用。“快照”風格的迭代器方法在創建迭代器時使用了對數組狀態的引用。此數組在迭代器的生存期內絕不會更改,因此不可能發生衝突,並且迭代器保證不會拋出 ConcurrentModificationException。自創建迭代器以後,迭代器就不會反映列表的添加、移除或者更改。不支持迭代器上更改元素的操作(移除、設置和添加)。這些方法將拋出 UnsupportedOperationException。

主要構造方法有:

[java] view plaincopy
  1. CopyOnWriteArrayList();  // 創建一個空列表。  
  2. CopyOnWriteArrayList(Collection<> c); //按照 Collection 的迭代器返回元素的順序,創建一個包含指定 Collection 的元素的列表。  
  3. CopyOnWriteArrayList(E[] toCopyIn);   //創建一個新的 CopyOnWriteArrayList,它保持給定數組的副本。  


CopyOnWriteArraySet是對其所有操作使用 CopyOnWriteArrayList 的 Set。因此,它共享以下相同的基本屬性:
  • 它最適合於 set 大小通常保持很小、只讀操作遠多於可變操作以及需要在遍歷期間防止線程間衝突的應用程序。
  • 它是線程安全的。
  • 因爲通常需要複製整個基礎數組,所以可變操作(添加、設置、移除,等等)的開銷巨大。
  • 迭代器不支持可變移除操作。
  • 使用迭代器進行遍歷的速度很快,並且不會與其他線程發生衝突。在構造迭代器時,迭代器依賴於不變的數組快照。 
主要構造方法包括:

[java] view plaincopy
  1. CopyOnWriteArraySet();   //創建一個空 set  
  2. CopyOnWriteArraySet(Collection<> c);   //創建一個包含指定 Collection 中所有元素的 set  

       

        講完併發集合類以後再回到本文剛開始的例子中,如果將Collection users = new ArrayList();改寫成Collection users = new CopyOnWriteArrayList();再運行程序,程序就會正常進行了,結果如下:

[java] view plaincopy
  1. 正在執行!  
  2. {name:'張三',age:28}  
  3. 正在執行!  
  4. 正在執行!  
  5. {name:'王五',age:31}  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章