nano7
nano7

Reputation: 2493

ArrayList - add "same" objects (same => equals, hashCode), Threads

Ive got one question. What happens when I try to add the "same" object twice to an ArrayList. With "the same" I mean an object of an individual class, which is identified as the same with equals() and hashCode(). It has different values for most of the member variables and was created from maybe different threads, but for equals() and hashCode() its the "same". Does the second object then replace the first object?

Also, what happens if two threads try to add those objects exactly at the same time to the ArrayList? Is this even possible? If yes, what happens?

Thank you! :-)

[EDIT] Thanks for all the answers! Should I use synchronizedList then rather then using "synchronize(list){}"? --> I read the docs, even with synchronizedList, for iterating synchronize(list) shall be used

[EDIT2] Can a synchronizedList be declared as a member variable? I tried, but it didnt work.

Upvotes: 12

Views: 41470

Answers (5)

mre
mre

Reputation: 44250

Does the second object then replace the first object?

No, most developers do explicit checks

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

Also, what happens if two threads try to add those objects exactly at the same time to the ArrayList? Is this even possible? If yes, what happens?

Yes, this is possible. If multiple threads write to/read from the same ArrayList, then use the synchronized keyword whenever you access this list

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

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

EDIT

As someone pointed out, I suppose checking whether or not the ArrayList contains the object to be added is quite expensive. If you want to ensure that the object is only added once, I'd follow the recommendation made below of using a LinkedHashSet. According to the API, when attempting to add to this data structure it

Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.

Upvotes: 7

RMT
RMT

Reputation: 7070

If you try to add the same object twice, it will work, or if you try to add 2 objects with everything the same, it will still work. It is not best practice to do that because its harder to maintain the list.

overall: you shouldn't do it

Upvotes: 1

Tom Tresansky
Tom Tresansky

Reputation: 19877

An ArrayList can contain multiple references to the same exact object (identity equivalence). It doesn't check equals() or hashCode() when adding objects.

You will just end up with two references in your ArrayList.

ArrayList is NOT thread-safe...so the behaviour if you try to have two threads add at the same time is undefined. Maybe try using a SynchronizedList if you want to do something like that.

Upvotes: 2

Jigar Joshi
Jigar Joshi

Reputation: 240928

It will allow to add simply. List has nothing to do with hashCode(), equals() while insertion it doesn't care for duplicate.

ArrayList isn't thread safe so you might not get desired result. you can have synchronizedList from Collections class

Upvotes: 4

Jon Skeet
Jon Skeet

Reputation: 1502076

No, ArrayList doesn't attempt to detect duplicates at all - you can have an ArrayList with the exact same reference appearing multiple times. If you want a collection to avoid duplicates, you need a Set implementation - and if you also want to preserve insertion order, you probably want LinkedHashSet.

Note, however, that without locking ArrayList should not be mutated from multiple threads in the first place - it's simply not meant to be a thread-safe collection in that way. Several threads can read from an ArrayList without synchronization, but not mutate it. From the docs:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list

If you want to mutate a collection from multiple threads without locking, I suggest you look at the collections in java.util.concurrent.

Upvotes: 16

Related Questions