Java ArrayList-添加“列表”;“相同”;对象(相同=>;等于,哈希代码),线程
我有一个问题。当我尝试向ArrayList添加两次“相同”对象时会发生什么。“相同”是指单个类的一个对象,它用equals()和hashCode()标识为相同。对于大多数成员变量,它有不同的值,并且可能是从不同的线程创建的,但是对于equals()和hashCode()则是“相同的”。 然后第二个对象是否替换第一个对象 另外,如果两个线程同时尝试将这些对象添加到ArrayList,会发生什么情况?这可能吗?如果是,会发生什么 谢谢!:-) [编辑]谢谢你的回答!我是否应该使用synchronizedList而不是使用“synchronize(list){}”?-->我阅读了文档,即使使用synchronizedList,也应使用Synchronized(list)进行迭代 [编辑二]Java ArrayList-添加“列表”;“相同”;对象(相同=>;等于,哈希代码),线程,java,multithreading,arraylist,equals,hashcode,Java,Multithreading,Arraylist,Equals,Hashcode,我有一个问题。当我尝试向ArrayList添加两次“相同”对象时会发生什么。“相同”是指单个类的一个对象,它用equals()和hashCode()标识为相同。对于大多数成员变量,它有不同的值,并且可能是从不同的线程创建的,但是对于equals()和hashCode()则是“相同的”。 然后第二个对象是否替换第一个对象 另外,如果两个线程同时尝试将这些对象添加到ArrayList,会发生什么情况?这可能吗?如果是,会发生什么 谢谢!:-) [编辑]谢谢你的回答!我是否应该使用synchroniz
synchronizedList是否可以声明为成员变量?我试过了,但没用 否,
ArrayList
根本不尝试检测重复项-您可以在一个ArrayList
中多次出现完全相同的引用。如果希望集合避免重复,则需要一个Set
实现—如果还希望保留插入顺序,则可能需要
但是,请注意,如果不锁定ArrayList
,那么首先就不应该从多个线程中进行变异,因为这样做并不意味着它是线程安全的集合。多个线程可以从ArrayList
读取数据,而无需同步,但不能对其进行变异。从文档中:
请注意,此实现是不同步的。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改该列表,则必须在外部对其进行同步。(结构修改是添加或删除一个或多个元素,或显式调整支持数组大小的任何操作;仅设置元素的值不是结构修改。)这通常通过在自然封装列表的某个对象上进行同步来完成。如果不存在此类对象,则应使用Collections.synchronizedList方法“包装”列表。最好在创建时执行此操作,以防止意外不同步地访问列表
如果您想在不锁定的情况下从多个线程中变异集合,我建议您查看中的集合。它允许简单地添加。列表与
hashCode()
,equals()
无关,但插入时不考虑重复
ArrayList
不是线程安全的,因此可能无法获得所需的结果。您可以从Collections
class中获得synchronizedList
,ArrayList
可以包含对同一确切对象的多个引用(标识等价)。添加对象时,它不会选中equals()
或hashCode()
您将在ArrayList中得到两个引用
ArrayList
不是线程安全的…因此,如果您试图同时添加两个线程,则行为是未定义的。如果你想做这样的事情,也许可以试着用一个
然后第二个对象是否替换
第一个对象
不,大多数开发人员都进行显式检查
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);
}
}
公共列表getFoos(){
已同步(列表){
退货清单;
}
}
公共无效添加Foo(Foo-Foo){
已同步(列表){
添加(foo);
}
}
编辑
正如有人指出的,我认为检查ArrayList
是否包含要添加的对象是相当昂贵的。如果您想确保只添加一次对象,我将按照下面的建议使用。根据API,当尝试将此数据结构
将指定的元素添加到此集合
如果它还没有出现。更多
形式上,添加指定的元素e
如果此集合不包含任何
元素e2使得(e==null?
e2==null:e.equals(e2))。如果这一套
已包含元素,调用
保持集合不变并返回
错
如果您尝试添加同一对象两次,它将起作用,或者如果您尝试添加两个具有相同内容的对象,它仍将起作用。这样做不是最佳做法,因为维护列表比较困难
总的来说:您不应该这样做-1对
ArrayList.contains的每次调用都是O(n)。这是一种创建唯一列表的糟糕方法LinkedHashSet
更好。但是当使用LinkedHashSet访问时,它也必须同步,对吗?那么为什么不使用synchronizedList呢?@nano7,当然它必须是同步的。更改集合并不意味着更改同步策略。你可以自由使用任何你想要的同步数据结构,但是如果你要使用LinkedHashSet
,我建议你使用synchronizedSet
。像这样?Set s=Collections.synchronizedSet(新LinkedHashSet());如何声明这种类型的成员变量?其类型是否为“LinkedHashSet()”?然后我是否手动创建synchronizedSet并将其设置为成员变量(使用强制转换)?如果将一个对象添加到列表中一次,则不能再次添加同一对象,因此不需要同步“添加”,不是吗?