在我们的应用程序中,我们在ArrayList.add(Object o)
操作上得到了一个ArrayIndexOutOfBounds异常。最明显的解释是线程安全,但我无法重新创建事件。我试过创建两个线程。在一个我添加元素,在另一个我正在删除它们(或清除数组),但我没有第二次得到异常。
我的意思是很明显它可以通过查看ArrayList的源代码来实现,但是能够演示它会很好。
我已经运行了这个测试很长一段时间没有任何例外:
public class Test {
static ArrayList a = new ArrayList();
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
while (true) {
if (a.size() > 0)
a.remove(0);
}
}
};
Thread t2 = new Thread() {
public void run() {
while (true) {
a.add(new Object());
}
}
};
t2.start();
Thread.sleep(100);
t1.start();
}
}
答案 0 :(得分:6)
感谢isnot2bad的评论,我在我的假设中发现了一个问题。 问题在于并发添加,而不是添加/删除。 我能够创建一个失败的测试:
static ArrayList a = new ArrayList(1);
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
while (true) {
a.add(new Object());
}
}
};
Thread t2 = new Thread() {
public void run() {
while (true) {
a = new ArrayList(1);
a.add(new Object());
a.add(new Object());
}
}
};
t2.start();
Thread.sleep(100);
t1.start();
}
在第一个帖子的添加行中,我得到了这个:
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 2
:)
答案 1 :(得分:2)
使用给定代码很难观察到任何错误,因为您实际上并未检查列表中存储的内容。我不能说得到一个ArrayIndexOutOfBoundsException
是不可能的,但是这将是非常罕见的,因为你只能在调整数组大小时获得一个,并且它很少调整大小。
如果检查删除的对象不是重复的,则更有可能看到意外行为:您只添加新对象,因此删除的线程永远不会看到同一个对象两次,对吧?不是这样:
import java.util.*;
public class Test {
static ArrayList a = new ArrayList();
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
Object x = null;
while (true) {
if (a.size() > 0) {
Object y = a.remove(0);
if (x == y) System.out.println("Duplicate!");
x = y;
}
}
}
};
Thread t2 = new Thread() {
public void run() {
while (true) {
a.add(new Object());
}
}
};
t2.start();
Thread.sleep(100);
t1.start();
}
}
在System.arrayCopy
调用期间添加对象时会发生这种情况:elementData[--size] = null
将错误的数组索引设置为null
,因为size
不再具有其在{{1}}中的值方法的开头。
答案 2 :(得分:1)
我可以通过添加更多的加法器线程来重现您的问题。
答案 3 :(得分:0)
让您的消费者线程比生产者睡眠时更少睡眠,例如20毫秒而不是100毫秒。这样,抛出异常的可能性要大得多。