For 循环中遇到的一个IndexOutOfBoundsException

一个工具类中有个监听集合(LinkedList listeners),添加和删除都通过synchronized的regist和unregist方法处理,但是在对其监听集合进行synchronized 的 for循环处理数据时还是出现了IndexOutOfBoundsException,百思不得其解。

public abstract class MapLocation {

    private LinkedList listeners = new LinkedList();

    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();
    }
} 

既然出现了IndexOutOfBoundsException,说明监听集合在循环过程中肯定被修改了,导致。既然已经同步,说明修改不可能其他线程在循环外部,只可能在循环的内部出现。最后终于发现在listener的实现中会调用unregist方法将当前listener从集合中remove。而循环中是从头到尾(1,2)获取每个数据项目,并从集合中remove掉自己,size是提前获取好的。这样导致集合中的数据跟size对不上。从而出现越界异常。
解决:如果循环从尾到头获取,虽然尾部的数据项目被remove掉,但是下次循环的index总是从上次remove掉的上一个,因此并无影响。
注意:如果删除时同一次循环同时删除多个数据项目。则会导致下一次循环取数据时拿不到数据报空指针异常,此时解决方法只有一个在另外的线程中删除(Iterator 或者自建线程。Iterator其实是在另外的线程中运行)。

你可能感兴趣的:(For 循环中遇到的一个IndexOutOfBoundsException)