<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
當一個代碼段正對集合進行枚舉而另一段代碼試圖修改這個集合時,就會發生常見的多線程問題。解決這一問題的方法是在處理前拷貝一份枚舉變量。
在撰寫多線程代碼時,你碰到過多少次下面的提示:
Exception in thread "main" java.util.ConcurrentModificationException
這個異常產生的原因有幾個。一是直接對集合調用刪除操作而不是在枚舉器上。二是不同的線程試圖對集合進行增刪操作的時候。
這個解決辦法的第一步就是同步代碼,使得你在枚舉的時候其它的線程不能增刪記錄。但是假如每個枚舉過程要進行復雜的計算或者是數據庫訪問的一部分的話,這個同步就會導致可怕的後果。為了減少負面影響,可以拷貝一個只讀的枚舉器,去掉同步,然後采用下列代碼所示的方法:
private List list;
public void add(Object obj) {
synchronized(list) {
list.add(obj);
}
}
public void perform( ) {
Iterator iterator = null;
synchronized(list) {
iterator = new CopiedIterator(list.iterator( ));
}
while(iterator.hasNext( )) {
// perform resource or cpu hungry work
}
}
重要的是記住,CopiedIterator不是一個克隆,只是一個只讀的拷貝,所以它並沒有保持原有的全部功能。最重要的是,不能再調用CopiedIterator.remove方法了。CopiedIterator.remove的實現如下:
public class CopiedIterator implements Iterator {
private Iterator iterator = null;
public CopiedIterator(Iterator itr) {
LinkedList list = new LinkedList( );
while(itr.hasNext( )) {
list.add(itr.next( ));
}
this.iterator = list.iterator( );
}
public boolean hasNext( ) {
return this.iterator.hasNext( );
}
public void remove( ) {
throw new UnsupportedOperationException("This is a read-only iterator.
");
}
public Object next( ) {
return this.iterator.next( );
}
}
枚舉器的只讀拷貝將用在同步狀態上的時間減少到最小,因此可以增強全局的效率。