ArrayList - 添加“相同”对象(相同=>等于,hashCode),线程

时间:2011-05-26 12:16:51

标签: java multithreading arraylist equals hashcode

我有一个问题。当我尝试将“相同”对象两次添加到ArrayList时会发生什么。 “相同”是指单个类的对象,使用equals()和hashCode()标识为相同。它对于大多数成员变量具有不同的值,并且可能是从不同的线程创建的,但对于equals()和hashCode(),它们是“相同的”。 第二个对象是否会替换第一个对象?

此外,如果两个线程试图将这些对象完全同时添加到ArrayList会发生什么?这甚至可能吗?如果是,会发生什么?

谢谢! :-)

[编辑]感谢所有答案!我应该使用synchronizedList,而不是使用“synchronize(list){}”吗? - >我阅读文档,即使使用synchronizedList,也可以使用迭代同步(list)

[EDIT2] 可以将synchronizedList声明为成员变量吗?我试过了,但它没有用。

5 个答案:

答案 0 :(得分:15)

不,ArrayList根本不会尝试检测重复项 - 您可以让ArrayList具有完全相同的引用多次出现。如果您希望集合避免重复,则需要Set实现 - 如果 想要保留插入顺序,则可能需要LinkedHashSet

但是,请注意,如果没有锁定ArrayList,首先应该从多个线程中突变 - 它本身并不意味着是一个线程安全的集合。几个线程可以在没有同步的情况下从ArrayList 读取,但不会改变它。来自文档:

  

请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,或显式调整后备数组的大小;仅设置元素的值不是结构修改。)这通常通过同步一些自然封装的对象来实现。名单。如果不存在此类对象,则应使用Collections.synchronizedList方法“包装”该列表。这最好在创建时完成,以防止意外地不同步访问列表

如果你想在不锁定的情况下改变多个线程的集合,我建议你看一下java.util.concurrent中的集合。

答案 1 :(得分:6)

  

然后替换第二个对象   第一个对象?

不,大多数开发人员都会进行明确的检查

if(!list.contains(foo)){
    list.add(foo);
}
  

此外,如果两个线程尝试会发生什么   准确地添加这些对象   同时到ArrayList?这是   甚至可能?如果是,会发生什么?

是的,这是可能的。如果多个线程写入/读取同一个ArrayList,则每次访问此列表时都使用synchronized关键字

public List<Foo> getFoos(){
    synchronized(list){
        return list;
    }
}

public void addFoo(Foo foo){
    synchronized(list){
        list.add(foo);
    }
}

修改

有人指出,我想检查ArrayList是否包含要添加的对象是非常昂贵的。如果您想确保只添加一次对象,我会遵循以下使用LinkedHashSet的建议。根据API,尝试add到此数据结构时

  

将指定的元素添加到此集合中   如果它还没有出现。更多   正式地,添加指定的元素e   如果此集合不包含此集合   元素e2这样(e == null?   e2 == null:e.equals(e2))。如果这个设定   已包含元素,调用   保持设置不变并返回   假的。

答案 2 :(得分:4)

它可以简单地添加。列表与hashCode()equals()无关,而插入则不关心重复。

ArrayList不是线程安全的,因此您可能无法获得所需的结果。您可以从synchronizedList班级

获得Collections

答案 3 :(得分:2)

ArrayList可以包含对同一个确切对象的多个引用(标识等效)。添加对象时,它不会检查equals()hashCode()

您最终将在ArrayList中找到两个引用。

ArrayList不是线程安全的...所以如果你试图同时添加两个线程的行为是未定义的。如果您想做类似的事情,也许可以尝试使用SynchronizedList

答案 4 :(得分:1)

如果您尝试将同一个对象添加两次,它将起作用,或者如果您尝试添加两个具有相同内容的对象,它仍然可以工作。这样做不是最佳做法,因为更难维护列表。

总的来说:你不应该这样做