當(dāng)一個(gè)代碼段正對(duì)集合進(jìn)行枚舉而另一段代碼試圖修改這個(gè)集合時(shí),就會(huì)發(fā)生常見(jiàn)的多線程問(wèn)題。解決這一問(wèn)題的方法是在處理前拷貝一份枚舉變量。
在撰寫(xiě)多線程代碼時(shí),你碰到過(guò)多少次下面的提示:
Exception in thread "main" java.util.ConcurrentModificationException
這個(gè)異常產(chǎn)生的原因有幾個(gè)。一是直接對(duì)集合調(diào)用刪除操作而不是在枚舉器上。二是不同的線程試圖對(duì)集合進(jìn)行增刪操作的時(shí)候。
這個(gè)解決辦法的第一步就是同步代碼,使得你在枚舉的時(shí)候其它的線程不能增刪記錄。但是假如每個(gè)枚舉過(guò)程要進(jìn)行復(fù)雜的計(jì)算或者是數(shù)據(jù)庫(kù)訪問(wèn)的一部分的話,這個(gè)同步就會(huì)導(dǎo)致可怕的后果。為了減少負(fù)面影響,可以拷貝一個(gè)只讀的枚舉器,去掉同步,然后采用下列代碼所示的方法:
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不是一個(gè)克隆,只是一個(gè)只讀的拷貝,所以它并沒(méi)有保持原有的全部功能。最重要的是,不能再調(diào)用CopiedIterator.remove方法了。CopiedIterator.remove的實(shí)現(xiàn)如下:
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( );
}
}
枚舉器的只讀拷貝將用在同步狀態(tài)上的時(shí)間減少到最小,因此可以增強(qiáng)全局的效率。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注