For 循环中遇到的一个IndexOutOfBoundsException

一个工具类中有个监听集合(LinkedList listeners),添加和删除都通过synchronized的regist和unregist方法处理,但是在对其监听集合进行synchronized 的 for循环处理数据时还是出现了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();
    }
} 

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,341评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,742评论 18 399
  • 集合框架: 1)特点:存储对象;长度可变;存储对象的类型可不同2)Collection(1)List:有序的;元素...
    Demo_Yang阅读 1,281评论 0 4
  • 法国的罗曼·罗兰写了一部书,叫做《名人传》,那么今天,我们就来聊聊名人背后的世界。 No.1「贝多芬」 提到贝多芬...
    airven阅读 222评论 2 1
  • 每天都重复着一样的生活模式,朝九晚五的工作,一如既往的赶公车,在熙熙攘攘的人群里沉默。 一大早起来,为了不迟到,排...
    夜白安阅读 952评论 0 0