5

在我们的应用程序中,我们在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();
}
}
4

4 回答 4

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 

:)

于 2013-09-24T13:55:16.363 回答
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.arrayCopyelementData[--size] = null将错误的数组索引设置为,null因为size不再具有它在方法开头的值。

于 2013-09-24T14:33:23.140 回答
1

只需添加更多加法器线程,我就可以重现您的问题。

于 2013-09-24T13:55:47.130 回答
0

使您的消费者线程睡眠比生产者睡眠少得多,例如 20 毫秒而不是 100 毫秒。这样抛出异常的机会就大得多。

于 2013-09-24T13:57:17.417 回答