Java中最常使用的就是集合了,而且處於效能的考慮,現在大部分人都不再使用Vector這種方法同步的集合了。新的集合庫帶來了更快的效能,同時也帶來了更多錯誤使用的可能。新集合庫效能的提升主要就是去掉了方法同步,可想而知,同步訪問時必然存在資料一致性問題。為了能使程式不會因為資料的不一致而造成其它錯誤,新集合庫在設計時採用了快速失敗機制(Fast-Fail),就是每次遍曆集合時都會判斷當前集合大小是否被修改,如果被修改,馬上拋出ConcurrentModificationException異常,停止程式繼續運行。因此集合初始化完成後,應避免在另一處被修改大小。看下面這個例子:
package com.bhr.ioat.testcollection;
import java.util.*;
public class TestRemove
{
public static void main(String[] args)
{
Collection cltn = new ArrayList();
for(int i=0; i<100000; i++){
cltn.add(new Integer(i));
}
new OtherThread(cltn).start();
try{
Thread.sleep(1000); //sleep 1 second, in order to ensure the new thread start up.
}catch(Exception e){
e.printStackTrace();
}
Iterator it = cltn.iterator();
while(it.hasNext()){
Object obj = it.next();
cltn.remove(obj);
//it.remove();
System.out.println("Remove one element from collection");
break;
}
}
}
class OtherThread extends Thread
{
public Collection cltn_;
public OtherThread(Collection cltn){
cltn_ = cltn;
//cltn_ = (Collection)(((ArrayList)cltn).clone());
}
public void run(){
Iterator it = cltn_.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
}
}
程式很簡單,開始初始化一個100000大小的ArrayList,然後傳給另一個類,隨後刪除集合中的一個元素,你會發現馬上就會拋出ConcurrentModificationException異常。
那是不是就不可以刪除元素了?是不是應該繼續使用Vector?當然不是,要不新集合的出現豈不是失去了意義。解決方案有兩個,(1)集合只在一處被使用,這自然沒有並發問題,不過還是不可以大膽修改,如果迴圈中刪除集合中的元素,一定要調用Iterator的remove方法,而不是Collection的remove方法,前者刪除後會修改Iterator的一個值,使得迴圈以為集合沒被修改,可以繼續進行,而調用後者沒有修改Iterator中的值,繼續迴圈同樣會拋出異常。至於添加元素,Iterator中沒有提供相應方法,所以如果在迴圈中添加,添加後就只能跳出迴圈了。(2)同一個集合在多處被使用,索性不要刪除了,本來這種情況就不應該修改集合大小,如果你決得集合大小的修改不會影響程式的正常邏輯,那麼使用時只好clone一個了。
上面只是實際中總結得一點經驗,如果大家有更好得方法,可以交流一下。
E-mail:bbs_9527@yahoo.com.cn