问题情况描述:
业务模块由多线程并发处理,处理结果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)
------解决思路----------------------
我觉得问题应该不在楼主贴出来的部分,而是在省略号之后的部分
如果多线程导致的话,楼主的debug出来的就不是那个样子了。
------解决思路----------------------
synchronized (this.clientAnalysisBeansList) {
this.clientAnalysisBeansList.addAll(clientAnalysisBeansList);
}
这是给List扩容吗?
------解决思路----------------------
我昨天后来看了一下ArrayList的源代码。
最大的可能还是你别的地方还有对 this.clientAnalysisBeansList 的操作导致的。
要解决这个问题也很简单,你还是用local的变量再new 一个 ArrayList,然后把类变量里的clientAnalysisBeansList并到新的ArrayList里,然后再进行操作。
最后再用同步块,把类变量的clientAnalysisBeansList清空,把你新的ArrayList再addAll进来。
------解决思路----------------------
仅仅这点代码肯定无法确定问题所在,不过可能性最大的就是多线程导致的,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,这个方法没有线程互斥,很容易出问题
但是后面我对他加锁了,还是会出现跳下标的这种奇葩问题,,,我没法证明问题肯定出在这里,,,所以很纠结,,,
那就别纠结跳下标的问题了。
按我给你的建议做,多个三五行代码而已