ArrayList.add()时报越界异常

今天遇到几个很诧异的越界异常:
List cmds = TerminalMaps.terminal_commands.get(mac);
if (cmds == null){
cmds = new ArrayList();

}

StringBuffer command = new StringBuffer();
command.append(Constant.CMD_START).append("register_response").append(Constant.CMD_ITEM_TOKENIAER).append("ok");

cmds.add(command.toString()); //在这一行报了个java.lang.ArrayIndexOutOfBoundsException: -1

还有一个remove时越界异常:
while (cmdList.size() > 0){
String cmd = cmdList.remove(0); //这儿也报越界异常
}

这两个越界异常的诡异极了, 而且很难重现.当我以为只是幻觉的时候, 他又时不时蹦出来恶心我一把.

请大家指教.

怀疑你是不是并发访问cmds 和 cmdList

如果单线程应该是不会有这种问题的:

cmds.add(command.toString()); //在这一行报了个java.lang.ArrayIndexOutOfBoundsException: -1

还有一个remove时越界异常:
while (cmdList.size() > 0){
String cmd = cmdList.remove(0); //这儿也报越界异常
}

ArrayList add实现
[code="java"] public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}[/code]
可能 size 超过int大小 造成负数引起 你看看 异常 索引多大

ArrayList的size 和 remove实现
[code="java"]public E remove(int index) {
RangeCheck(index);

modCount++;
E oldValue = (E) elementData[index];

int numMoved = size - index - 1;
if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null; // Let gc do its work

return oldValue;
}
private void RangeCheck(int index) {
if (index >= size)
    throw new IndexOutOfBoundsException(
    "Index: "+index+", Size: "+size);
}

[/code]

1、RangeCheck 如果index >=size 抛出越界;
2、elementData[--size] 如果size=0 抛出
3、如果index<0抛出

你的代码
while (cmdList.size() > 0){ //当size() > 0 在该点单线程的话绝对不会出现size=0 而且index >=0 没有问题的
String cmd = cmdList.remove(0); //移除第0个

}

可能是多线程并发访问造成的,建议
1、List cmds = new ArrayList(TerminalMaps.terminal_commands.get(mac)); ---做个副本

2、cmdList也一样做个本地副本

还有一个remove时越界异常:
while (cmdList.size() > 0){
String cmd = cmdList.remove(0); //这儿也报越界异常
}
第一次进入while存在0的元素是没问题的,当第二次进入0的元素已经被移除。所以会有
越界异常

只有两种可能会引起这种情况:
1。多线程的并发访问导致的,需要有外部同步机制。
2。List cmds可能是List的特殊实现,检查它的类型。

第一个问题:
ArrayList.add不会报越界异常, 最多堆OutOfMemory,你这里
[code="java"]List cmds = TerminalMaps.terminal_commands.get(mac); [/code] ,起作用的应该是这句吧,看看这个怎么实现的。

第二个问题:
并发情况下,有可能发生这个问题,2个线程都进入了while循环,结果第2个remove(0)的就会报越界异常。