I have a question. I think i know the answer but for some reason i prefer to ask for it here.
So here is the scenario:
I have an Object which has a list as a field. Then i have a method that returns the list as an unmodifiableList.
The Oject class has other methods that add elements to the list.
So lets imagine a case where one thread is iterating throught the unmodifiable list and another thread that is adding elements to the list using the Object class method.
How do i make this thread safe? If i synchronize the unmodifiableList and the list itselft will it make it thread safe? After all they are two different object where the unmodifiableList has a field which is the naked list itselft.
You need to make the "naked" list synchronized:
private List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());
But beware: that will only make sure the list internal state is coherent. As soon as you iterate on the list, you can't prevent a modification to the list to happen between two calls to the list iterator. So nothing will prevent a ConcurrentModificationException to happen in that case. To prevent that, you should not return any reference (even an indirect one) to the list. All modifications and iterations to the list should be encapsulated in your class, and properly synchronized.
You can return an unmodifiable-clone of original list to the caller.
The disadvantage is that the caller may end up with a "stale" version of the list. However, by this way you achieve safe iterations. In concurrent world, it is OK to return last successfully updated data to the caller.
public List<Thing> getThings() {
List<Thing> copytOfThings = new ArrayList<>();
copyOfThings.addAll(_things); //original list items.
return Collections.unmodifiableList(copyOfThings);
}
There are a couple of ways you could do this:
Return a copy of the list, rather than an unmodifiable view of it
Rather than using the iterator, use List.get(int)
Related
In ArrayList api we have:
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.
Here what is meant by "This is typically accomplished by synchronizing on some object that naturally encapsulates the list"? How this related to concurrent modification exception?
from ArrayList
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:
List list = Collections.synchronizedList(new ArrayList(...));
By "naturally encapsulates" it means that if the list is a field of an object, but the list is not publically accessible suppose the following:
class ParkingLot{
private ArrayList<Cars> spots;
public boolean park(int spotNumber, Car car){
if( spots.get(spotNumber)==null){
spot.set(spotNumber,car);
return true;
}
return false;
}
}
In this case ParkinLot would encapulate the list spot. If you were to try and call park(), you'd want to synchronize on the ParkingLot object to prevent two threads trying to park a car in the same spot at the same time.
It is related to a ConcurrentModificationException in that it prevents you from changing the list from separate threads simultaneously (by synchronizing), which could leave the list in an inconsistent state (ie Two cars parking at the same time thinking they've successfully parked).
Here what is meant by "This is typically accomplished by synchronizing
on some object that naturally encapsulates the list"
If you have a class which encapsulates an ArrayList then if you synchronize on the wrapper object than the underlying ArrayList will also be synchronized. e.g.
class MyClasss{
private final ArrayList list;
......
......
......
}
If you synchronize on the instance of MyClass than the underlying list is also synchronized and the all the read / write will be serialized e.g.
class MyClasss{
private final ArrayList list;
......
......
......
public void fun(){
synchronized(this){
list.add(....)
}
}
How this related to concurrent modification exception?
Before answering the above question you need to understand how ConcurrentModificationException is thrown by JVM.
ConcurrentModificationException is implemented in java by checking the modification count of each Collection. Every time you do an operation it compares the modification count before doing the operation and after doing the operation.
So if you synchronize the Collection then simultaneous modification of the modification count will not happen resulting in not throwing the ConcurrentModificationException.
Hope it helps.
Why not use Vector instead? It's already synchronized.
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.
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.
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.
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
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.
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
I have a general question regarding synchronized List.
Lets say that in the constructor I am createing a list
List synchronizedList = Collections.synchronizedList(list);
and I have one method adds an object to the list.
public void add(String s){
synchronizedList.add(s)
}
There is another thread that checks every few seconds if there are a few rows , dump it to a file and deletes them all.
Now lets say I iterate each row and save it to the db.
after all iteration I clear the list.
How does the multithread support help me?
I could add an element to the list just before the clear() in the other thread occurs .
Unless I manage the lock myself (which I dont realy need a synched list for that ) it myself.
The synchronized list returned by Collections won't help in your case. It's only good if you need to guarantee serial access to individual method calls. If you need to synchronize around a larger set of operations, then you need to manually wrap that code in a synchronized block. The Javadoc states:
It is imperative that the user manually synchronize on the returned list when iterating over it.
If your list is used elsewhere you can at least safeguard it from individual method calls that would otherwise not be thread-safe. If you're entirely managing the list however, you can just add a synchronized block to your add method and use the same lock that you'll use when iterating over it.
synchronizedList indeed only guarantees that every method call on the list is synchronized. If you need multiple operations to be done in a synchronized way, you have to handle the synchronization yourself.
BTW, this is explicitely said in the javadoc for Collections.synchronizedList :
It is imperative that the user
manually synchronize on the returned
list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
synchronized list means that all the operations on that list are guaranteed to be atomic. The scenario you describe requires to have some locking outside the list. Consider semaphores or making synchronized block to implement monitors. Take a look at java.util.concurrent.
I'm looking at the static method
Collections.synchronizedList(List<T> list)
Javadoc says
It is imperative that the user manually synchronize on the returned list when iterating over it...
What's the purpose of creating a synchronized list if I still have to manually synchronize it?
The reason why you would use
Collections.synchronizedList(List<T> list)
is because all the methods but the iterator are synchronized using the list itself as the mutex so you don't have to do
synchronized(list) {
list.add(type);
}
Instead you can just do
list.add(type);
and it will be thread safe.
The only method which isn't synchronized is when iterating the list. The list iterator can't be return in a synchronized fashion, since you will be iterating through it afterwards which is why it is required to manually synchronize the list. So in conclusion, you only have to synchronize the list when iterating over it, everything else you don't have to.
The java collections tutorial explains this. Basically, each iteration reauires multiple calls to the underlying collection. These calls muct be atomicised as a single 'transaction'.
I'm iterating over a JRE Collection which enforces the fail-fast iterator concept, and thus will throw a ConcurrentModificationException if the Collection is modified while iterating, other than by using the Iterator.remove() method . However, I need to remove an object's "logical partner" if the object meets a condition. Thus preventing the partner from also being processed. How can I do that? Perhaps by using better collection type for this purpose?
Example.
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
Thanks.
It's not a fault of the collection, it's the way you're using it. Modifying the collection while halfway through an iteration leads to this error (which is a good thing as the iteration would in general be impossible to continue unambiguously).
Edit: Having reread the question this approach won't work, though I'm leaving it here as an example of how to avoid this problem in the general case.
What you want is something like this:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
If you remove objects through the Iterator itself, it's aware of the removal and everything works as you'd expect. Note that while I think all standard collections work nicely in this respect, Iterators are not required to implement the remove() method so if you have no control over the class of myCollection (and thus the implementation class of the returned iterator) you might need to put more safety checks in there.
An alternative approach (say, if you can't guarantee the iterator supports remove() and you require this functionality) is to create a copy of the collection to iterate over, then remove the elements from the original collection.
Edit: You can probably use this latter technique to achieve what you want, but then you still end up coming back to the reason why iterators throw the exception in the first place: What should the iteration do if you remove an element it hasn't yet reached? Removing (or not) the current element is relatively well-defined, but you talk about removing the current element's partner, which I presume could be at a random point in the iterable. Since there's no clear way that this should be handled, you'll need to provide some form of logic yourself to cope with this. In which case, I'd lean towards creating and populating a new collection during the iteration, and then assigning this to the myCollection variable at the end. If this isn't possible, then keeping track of the partner elements to remove and calling myCollection.removeAll would be the way to go.
You want to remove an item from a list and continue to iterate on the same list. Can you implement a two-step solution where in step 1 you collect the items to be removed in an interim collection and in step 2 remove them after identifying them?
Some thoughts (it depends on what exactly the relationship is between the two objects in the collection):
A Map with the object as the key and the partner as the value.
A CopyOnWriteArrayList, but you have to notice when you hit the partner
Make a copy into a different Collection object, and iterate over one, removing the other. If this original Collection can be a Set, that would certaily be helpful in removal.
You could try finding all the items to remove first and then remove them once you have finished processing the entire list. Skipping over the deleted items as you find them.
myCollection<BusinessObject>
List<BusinessObject> deletedObjects = new ArrayList(myCollection.size());
for (BusinessObject anObject : myCollection)
{
if (!deletedObjects.contains(anObject))
{
if (someConditionIsTrue)
{
deletedObjects.add(anObjectsPartner);
}
}
}
myCollection.removeAll(deletedObjects);
CopyOnWriteArrayList will do what you want.
Why not use a Collection of all the original BusinessObject and then a separate class (such as a Map) which associates them (ie creates partner)? Put these both as a composite elements in it's own class so that you can always remove the Partner when Business object is removed. Don't make it the responsibility of the caller every time they need to remove a BusinessObject from the Collection.
IE
class BusinessObjectCollection implements Collection<BusinessObject> {
Collection<BusinessObject> objects;
Map<BusinessObject, BusinessObject> associations;
public void remove(BusinessObject o) {
...
// remove from collection and dissasociate...
}
}
The best answer is the second, use an iterator.