一個(gè)工具類中有個(gè)監(jiān)聽集合(LinkedList listeners),添加和刪除都通過synchronized的regist和unregist方法處理,但是在對其監(jiān)聽集合進(jìn)行synchronized 的 for循環(huán)處理數(shù)據(jù)時(shí)還是出現(xiàn)了IndexOutOfBoundsException,百思不得其解。
public abstract class MapLocation {
private LinkedList<ILocationListener> listeners = new LinkedList<ILocationListener>();
public boolean registLocationListener(ILocationListener listener) {
if (listener == null) {
return false;
}
synchronized (listeners) {
if (listeners.contains(listener)) {
return false;
}
listeners.add(listener);
return true;
}
}
public boolean unregistLocationListener(ILocationListener listener) {
if (listener == null) {
return false;
}
synchronized (listeners) {
return listeners.remove(listener);
}
}
protected void dispatchLocation(final LocationEntry le) {
synchronized (listeners) {
int size = listeners.size();
// for (int i = 0; i < size; i++) { //1
for (int i = size - 1; i > 0; i--) {//3
listeners.get(i).onLocationReceive(null, le);
}
}
}
protected void dispatchLocationFailed() {
synchronized (listeners) {
int size = listeners.size();
// for (int i = 0; i < size; i++) {//2
for (int i = size - 1; i > 0; i--) {//4
listeners.get(i).onLocationFailed();
}
}
}
public static interface ILocationListener {
public void onLocationReceive(String fromHID, LocationEntry le);
void onLocationFailed();
}
}
既然出現(xiàn)了IndexOutOfBoundsException,說明監(jiān)聽集合在循環(huán)過程中肯定被修改了,導(dǎo)致。既然已經(jīng)同步,說明修改不可能其他線程在循環(huán)外部,只可能在循環(huán)的內(nèi)部出現(xiàn)。最后終于發(fā)現(xiàn)在listener的實(shí)現(xiàn)中會(huì)調(diào)用unregist方法將當(dāng)前l(fā)istener從集合中remove。而循環(huán)中是從頭到尾(1,2)獲取每個(gè)數(shù)據(jù)項(xiàng)目,并從集合中remove掉自己,size是提前獲取好的。這樣導(dǎo)致集合中的數(shù)據(jù)跟size對不上。從而出現(xiàn)越界異常。
解決:如果循環(huán)從尾到頭獲取,雖然尾部的數(shù)據(jù)項(xiàng)目被remove掉,但是下次循環(huán)的index總是從上次remove掉的上一個(gè),因此并無影響。
注意:如果刪除時(shí)同一次循環(huán)同時(shí)刪除多個(gè)數(shù)據(jù)項(xiàng)目。則會(huì)導(dǎo)致下一次循環(huán)取數(shù)據(jù)時(shí)拿不到數(shù)據(jù)報(bào)空指針異常,此時(shí)解決方法只有一個(gè)在另外的線程中刪除(Iterator 或者自建線程。Iterator其實(shí)是在另外的線程中運(yùn)行)。