ArrayList - 添加"相同"对象(same => equals,hashCode),Threads

nan*_*no7 9 java multithreading equals arraylist hashcode

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

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

谢谢!:-)

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

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

Jon*_*eet 15

不,ArrayList不会尝试完全检测重复 - 您可以ArrayList使用完全相同的参考多次出现.如果你想有一个集合避免重复,你需要一个Set实现-如果你想保留插入顺序,你可能想LinkedHashSet.

但请注意,如果没有锁定ArrayList应该不是从多个线程在第一时间被突变-它只是并不意味着要以这种方式线程安全的集合.几个线程可以从没有同步的读取ArrayList,但不能改变它.来自文档:

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

如果你想在没有锁定的情况下从多个线程变异集合,我建议你看一下这些集合java.util.concurrent.


mre*_*mre 6

第二个对象是否会替换第一个对象?

不,大多数开发人员都做了明确的检

if(!list.contains(foo)){
    list.add(foo);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

public void addFoo(Foo foo){
    synchronized(list){
        list.add(foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

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

如果指定的元素尚不存在,则将其添加到此集合中.更正式地,如果此集合不包含元素e2(e == null?e2 == null:e.equals(e2)),则将指定元素e添加到此集合.如果此set已包含该元素,则调用将保持set不变并返回false.