java ArrayList addAll 出现下标缺失,该怎么解决

   阅读
java ArrayList addAll 出现下标缺失
本帖最后由 w837956 于 2015-02-03 20:53:43 编辑
问题情况描述:
业务模块由多线程并发处理,处理结果ArrayList 由接口A回调返回,接口实现类中有一个ArrayList 在接口实现中通过调用addAll 将返回的数据集中到一个list中,待多线程中的业务处理完成返回后,用sql的事务一次更新到数据库但是在提交到数据库的时候出现空指针,通过debug后发现空指针的原因是因为list存在跳下标的问题(见下图),问题随机出现没有规律并且正常情况下的list长度为111,缺失下标后打印的长度还是111,addAll到list 部分已经加了同步.请大神解惑


synchronized (this.clientAnalysisBeansList) {
this.clientAnalysisBeansList.addAll(clientAnalysisBeansList);
}
for(int i = 0 ; i < this.clientAnalysisBeansList.size() ; i++){
ClientAnalysisBean temp = this.clientAnalysisBeansList.get(i);
        stmt.addBatch("UPDATE FClientDisplay SET FPoint='"+temp.getFPoint()+"',........);//问题代码
                       //因为没有对应的下标,所以报空指针,求原因?
}

------解决思路----------------------
仅仅这点代码肯定无法确定问题所在,不过可能性最大的就是多线程导致的,ArrayList本身并非线程安全的,建议自己实现一个线程安全的List,在你自己实现的List中可以使用ArrayList来保存数据,只是对add,addall等方法进行同步控制。
------解决思路----------------------
试试Collections.synchronizedList(List<T> list)
------解决思路----------------------
引用:
仅仅这点代码肯定无法确定问题所在,不过可能性最大的就是多线程导致的,ArrayList本身并非线程安全的,建议自己实现一个线程安全的List,在你自己实现的List中可以使用ArrayList来保存数据,只是对add,addall等方法进行同步控制。


我觉得问题应该不在楼主贴出来的部分,而是在省略号之后的部分

如果多线程导致的话,楼主的debug出来的就不是那个样子了。


------解决思路----------------------
synchronized (this.clientAnalysisBeansList) {
            this.clientAnalysisBeansList.addAll(clientAnalysisBeansList);
 }
这是给List扩容吗?
------解决思路----------------------
引用:
Quote: 引用:

仅仅这点代码肯定无法确定问题所在,不过可能性最大的就是多线程导致的,ArrayList本身并非线程安全的,建议自己实现一个线程安全的List,在你自己实现的List中可以使用ArrayList来保存数据,只是对add,addall等方法进行同步控制。


自己实现list还是一样的加锁做同步,我在执行addAll时加了锁也是不行的,有时候半天都不会出这个问题,有时候一会就会出现好几次,我主要是想知道为什么会出现下标跳跃的问题,(理论上我直接用vector应该可以避免) 难道是ArrayList在执行arraycopy的时候出现的问题?下标少一个,但是看list的size还是够的,,,好奇怪


我昨天后来看了一下ArrayList的源代码。

最大的可能还是你别的地方还有对 this.clientAnalysisBeansList 的操作导致的。

要解决这个问题也很简单,你还是用local的变量再new 一个 ArrayList,然后把类变量里的clientAnalysisBeansList并到新的ArrayList里,然后再进行操作。

最后再用同步块,把类变量的clientAnalysisBeansList清空,把你新的ArrayList再addAll进来。

------解决思路----------------------
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

仅仅这点代码肯定无法确定问题所在,不过可能性最大的就是多线程导致的,ArrayList本身并非线程安全的,建议自己实现一个线程安全的List,在你自己实现的List中可以使用ArrayList来保存数据,只是对add,addall等方法进行同步控制。


自己实现list还是一样的加锁做同步,我在执行addAll时加了锁也是不行的,有时候半天都不会出这个问题,有时候一会就会出现好几次,我主要是想知道为什么会出现下标跳跃的问题,(理论上我直接用vector应该可以避免) 难道是ArrayList在执行arraycopy的时候出现的问题?下标少一个,但是看list的size还是够的,,,好奇怪


我昨天后来看了一下ArrayList的源代码。

最大的可能还是你别的地方还有对 this.clientAnalysisBeansList 的操作导致的。

要解决这个问题也很简单,你还是用local的变量再new 一个 ArrayList,然后把类变量里的clientAnalysisBeansList并到新的ArrayList里,然后再进行操作。

最后再用同步块,把类变量的clientAnalysisBeansList清空,把你新的ArrayList再addAll进来。


在所有线程返回以前是没有对 this.clientAnalysisBeansList 的操作的,(我刚检查了代码)
public boolean addAll(int index, Collection<? extends E> c) {
    if (index > size 
------解决思路----------------------
 index < 0)
        throw new IndexOutOfBoundsException(
        "Index: " + index + ", Size: " + size);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacity(size + numNew);  // Increments modCount

    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                 numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
    }

我认为最大的可能性就是在上面的arraycopy产生的,
一个线程返回数据后list执行addAll,同时另外一个线程返回了,也去执行这个addAll,这个方法没有线程互斥,很容易出问题
但是后面我对他加锁了,还是会出现跳下标的这种奇葩问题,,,我没法证明问题肯定出在这里,,,所以很纠结,,,


那就别纠结跳下标的问题了。

按我给你的建议做,多个三五行代码而已
阅读