For 循環(huán)中遇到的一個(gè)IndexOutOfBoundsException

一個(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)行)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,818評論 11 349
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,740評論 18 399
  • 集合框架: 1)特點(diǎn):存儲(chǔ)對象;長度可變;存儲(chǔ)對象的類型可不同2)Collection(1)List:有序的;元素...
    Demo_Yang閱讀 1,386評論 0 4
  • 法國的羅曼·羅蘭寫了一部書,叫做《名人傳》,那么今天,我們就來聊聊名人背后的世界。 No.1「貝多芬」 提到貝多芬...
    airven閱讀 272評論 2 1
  • 每天都重復(fù)著一樣的生活模式,朝九晚五的工作,一如既往的趕公車,在熙熙攘攘的人群里沉默。 一大早起來,為了不遲到,排...
    夜白安閱讀 981評論 0 0

友情鏈接更多精彩內(nèi)容