5

问题1:

指定 ArrayList 的大小是否有意义?我知道我的 List 中将包含多少元素,事先指定大小是否好,或者甚至无关紧要。

List<String> list = new ArrayList<String>(1);
list.add("Hello");

List<String> newList = new ArrayList<String>();
newList.add("Hello");

问题2:

java.util.ConcurrentModificationException 当您在迭代同一集合时操作(添加、删除)集合时发生。Does that mean there is a thread which is modifying the ArrayList and another Thread iterating the same object.

问题3

谁能告诉我如何锁定列表?

4

4 回答 4

8
  1. 如果您要添加很多项目,这很重要,因为这意味着集合不需要在进行过程中不断复制其内部缓冲区。使用一个小列表不会有太大的不同。请注意,您没有指定的大小-ArrayList您正在指定其初始容量

    List<String> list = new ArrayList<String>(10000);
    System.out.println(list.size()); // 0
    

    您仍然需要向其中添加项目以更改大小 - 但您可以在需要执行内部复制之前将项目添加到其容量。

  2. 不,不必涉及额外的线程。这只是意味着您在迭代集合时已经修改了集合。这可以很容易地在一个线程中:

    for (String item : items) {
        items.add("Foo"); // The next iteration step will fail.
    }
    
  3. 您需要提供更多上下文。通常,在对列表执行某些操作时获取锁更有意义。

于 2012-11-10T18:07:41.583 回答
1

Q1:这就是 ArrayList 的样子

public ArrayList{
    private int[] elementData;
    private int size;
}

构造 ArrayList 时,会自动初始化数组的大小。当空间不足时,大小会自动调整为原始大小的 1.5 倍。

Q2:你完全正确。“例如,通常不允许一个线程在另一个线程对其进行迭代时修改集合。通常,在这些情况下,迭代的结果是不确定的。一些迭代器实现(包括所有通用集合的实现)如果检测到这种行为,JRE 提供的实现可能会选择抛出这个异常。这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,而不是在不确定的时间冒着任意的、非确定性的行为的风险在将来。” -java 文档http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ConcurrentModificationException.html

Q3:锁定您使用的列表

Collections.unmodifiableList(list);

这适用于所有集合,并且它禁止用户更改数据。换句话说,它为用户提供了“只读”副本。您可以在此处阅读有关集合类的更多信息。http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html

于 2012-11-10T18:17:38.797 回答
1

关于问题 3: 锁定列表有两种方法

1)隐式监视器锁:如果您使用集合的工厂方法创建一个同步列表,那么您可以使用包装器对象来创建锁。

    List<T> list = new ArrayList<T>();
    List<T> slist = Collections.synchronizedList(list);
    synchoronized(slist) {
    //code
    } 

在这种情况下,slist 将用于在迭代和任何复合操作期间进行锁定。

2)您可以使用对象类作为锁

    Object lock = new Object();
    synchronized (lock) {
       // ...
     }
于 2012-11-10T18:33:08.967 回答
1
  1. 如果列表很大,那么值得声明初始大小。为什么?因为当你创建一个 ArrayList 时,它的初始大小通常是 ~10。当您添加新项目并且初始大小不够时,ArrayList 会分配更多内存,并且所有元素都会重新定位,这需要时间。

  2. 不,不需要另一个线程。当您遍历列表并在循环主体中添加或删除它的元素时,可能会发生此异常。然后你必须使用迭代器。

  3. 锁定列表是什么意思?您想让它成为线程安全的还是禁用添加/删除它的元素?在第二种情况下,您想使用unmodifiableCollection方法 in java.util.Collections

于 2012-11-10T18:07:30.613 回答