Does the unmodifiable wrapper for java collections make them thread safe? - java

I need to make an ArrayList of ArrayLists thread safe. I also cannot have the client making changes to the collection. Will the unmodifiable wrapper make it thread safe or do I need two wrappers on the collection?

It depends. The wrapper will only prevent changes to the collection it wraps, not to the objects in the collection. If you have an ArrayList of ArrayLists, the global List as well as each of its element Lists need to be wrapped separately, and you may also have to do something for the contents of those lists. Finally, you have to make sure that the original list objects are not changed, since the wrapper only prevents changes through the wrapper reference, not to the original object.
You do NOT need the synchronized wrapper in this case.

On a related topic - I've seen several replies suggesting using synchronized collection in order to achieve thread safety.
Using synchronized version of a collection doesn't make it "thread safe" - although each operation (insert, count etc.) is protected by mutex when combining two operations there is no guarantee that they would execute atomically.
For example the following code is not thread safe (even with a synchronized queue):
if(queue.Count > 0)
{
queue.Add(...);
}

The unmodifiable wrapper only prevents changes to the structure of the list that it applies to. If this list contains other lists and you have threads trying to modify these nested lists, then you are not protected against concurrent modification risks.

From looking at the Collections source, it looks like Unmodifiable does not make it synchronized.
static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
implements Set<E>, Serializable;
static class UnmodifiableCollection<E> implements Collection<E>, Serializable;
the synchronized class wrappers have a mutex object in them to do the synchronized parts, so looks like you need to use both to get both. Or roll your own!

I believe that because the UnmodifiableList wrapper stores the ArrayList to a final field, any read methods on the wrapper will see the list as it was when the wrapper was constructed as long as the list isn't modified after the wrapper is created, and as long as the mutable ArrayLists inside the wrapper aren't modified (which the wrapper can't protect against).

It will be thread-safe if the unmodifiable view is safely published, and the modifiable original is never ever modified (including all objects recursively contained in the collection!) after publication of the unmodifiable view.
If you want to keep modifying the original, then you can either create a defensive copy of the object graph of your collection and return an unmodifiable view of that, or use an inherently thread-safe list to begin with, and return an unmodifiable view of that.
You cannot return an unmodifiableList(synchonizedList(theList)) if you still intend to access theList unsynchronized afterwards; if mutable state is shared between multiple threads, then all threads must synchronize on the same locks when they access that state.

An immutable object is by definition thread safe (assuming no-one retains references to the original collections), so synchronization is not necessary.
Wrapping the outer ArrayList using Collections.unmodifiableList()
prevents the client from changing its contents (and thus makes it thread
safe), but the inner ArrayLists are still mutable.
Wrapping the inner ArrayLists using Collections.unmodifiableList() too
prevents the client from changing their contents (and thus makes them
thread safe), which is what you need.
Let us know if this solution causes problems (overhead, memory usage etc);
other solutions may be applicable to your problem. :)
EDIT: Of course, if the lists are modified they are NOT thread safe. I assumed no further edits were to be made.

Not sure if I understood what you are trying to do, but I'd say the answer in most cases is "No".
If you setup an ArrayList of ArrayList and both, the outer and inner lists can never be changed after creation (and during creation only one thread will have access to either inner and outer lists), they are probably thread safe by a wrapper (if both, outer and inner lists are wrapped in such a way that modifying them is impossible). All read-only operations on ArrayLists are most likely thread-safe. However, Sun does not guarantee them to be thread-safe (also not for read-only operations), so even though it might work right now, it could break in the future (if Sun creates some internal caching of data for quicker access for example).

This is neccessary if:
There is still a reference to the original modifiable list.
The list will possibly be accessed though an iterator.
If you intend to read from the ArrayList by index only you could assume this is thread-safe.
When in doubt, chose the synchronized wrapper.

Related

Why do synchronized wrappers exist for List,Set,Map when there is Collections.synchronizedCollection()

Does anyone know why should I (for example) put my List inside Collections.syncrhonizedList() instead of Collections.synchronizedCollection()? Do they work the same? Same applies to Map,Set.
Another thing. Why there isn't Collections.synchronizedQueue()?
When you are using synchronizedCollection() to synchronize an ArrayList, the list-specific methods are not synchronized, so the more concrete method, the better. Beware that method Collections.synchronizedList() will synchronize all the accesses to the backed list except while iterating which still needs to be done within a synchronized block with the synchronized List instance as object's monitor. One more thing, when you create synchronized collection using Collections.synchronizedCollection like this :
Collection c = Collections.synchronizedCollection(yourCollection);
Then, according to documentation, the returned collection does not pass the hashCode and equals operations through to the backing collection, but relies on Object's equals and hashCode methods. This is necessary to preserve the contracts of these operations in the case that the backing collection is a set or a list.

HashSet and multithreading

I work on Java 7.
I want to know if the method contains is thread-safe on HashSet object.
The HashSet is initialized by one thread. Then we wrap the HashSet with unmodifiable collection (Collections.unmodifiableSet). After initialization, multiple threads call only the method contains.
When I read the Javadoc, it's unclear for me.
On HashSet Javadoc we can read
This class implements the Set interface, backed by a hash table (actually a HashMap instance).
...
Note that this implementation is not synchronized.
And on the HashMap Javadoc, we can read:
Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.)
For me, this means the method contains is not a structural modification.
So multiple call to the method contains is it thread-safe?
If it's true: Is it guaranteed on all implementation of JVM (like IBM JVM)?
In general, there can be no concurrency race (and thus conflict) solely between read operations. Concurrency problems arise between read and write operations. So, multiple read operations interleaved are always thread-safe (if we assume that such a notion of thread-safety is well defined).
Now, there is one more case where there might be a concurrency issue and this is during the initialisation of the data structure, since this can be considered the only modification (write operation) in your case. In order to make sure that all the subsequent contains() invocations will see the fully initialised Set, you have to make sure that it's correctly initialised. This concept is defined as "safe-publication" in Java and you can read more about it here or in the book "Java Concurrency in Practice" book.
To conclude, Collections.unmodifiableSet() publishes the result in a safe way through a final field. So, yes you can be sure that all contains() will see the fully initialised Set

What java List is suitable for thread safe on addAll and clear

I only call addAll and clear of the List, but need it to thread-safe, is there any existing List for this ? Thanks
List is not-synchronized.
So it is not thread-safe.
If you want it as thread-safe means it is possible to make the list as thread-safe, you can use the
Collections.synchronizedList(List list)
A list created using Collections.synchronizedList(List list) will satisfy those requirements, provided that the synchronized list is the target object in the addAll(...) call, and never the parameter.
If the synchronized list (created as above) is the argument, then the problem is that addAll(list) iterates the argument list, and iterating a synchronized list is not atomic. If another thread updates list while it is being added, the you are liable to get a ConcurrentModificationException.
If you need to do the addAll(list) in a thread-safe fashion in the face of concurrent updates to list, then you need to make list a CopyOnWriteArrayList.
There is a concurrent list implementation in java.util.concurrent. CopyOnWriteArrayList in particular.
If you want to use exsting list as Synchronised one, go for Collections.synchronizedList(list) or you are creating targeted list, then you can go for CopyOnWriteArrayList
CopyOnWriteArrayList is a concurrent replacement for synchronizedList that offers better concurrency in some common situations & eliminates the need to lock or copy the collection during iteration.
The copy on write collections derive their thread safety from the fact that as an effectively immutable object is properly published, no further synchronization is required when accessing it. They implement mutability by creating & republishing a new copy of the collection everytime it is modified. The collection does not throw ConcurrentModificationException regardless of subsequent modifications.

How to perform clone() on Sets.newSetFromMap(map)

Previous code is like; to avoid ConcurrentModificationException on a Vector; where ever iteration is required; it was performing inside synchronized block on that Vector. So It is hitting very poor performance by making multiple threads into BLOCKED state to acquire lock on that Vector at different APIs.
I have decided to replace Vector to Collections.newSetFromMap(new ConcurrentHashMap<psConference,Boolean>()); in my project.
So after changing Vector into Concurrent collection; i have removed all SYNCH blocks.
But the problem here is some of my code is performing clone() on that Vector.
How to do the same on here since i have only Set interface ?
Vector clone() is Deep cloning or Shallow cloning ?
Also pls tell me the significance of Boolean at ConcurrentHashMap<psConference,Boolean>
But the problem here is some of my code is performing clone() on that
Vector.
How to do the same on here since i have only Set interface ?
You are working with a Set now, not a Vector. Your Set is backed by a ConcurrentHashMap, thus is safe to iterate concurrently. Rather then cloning i would suggest you to use a copy constructor.
But be aware (from the javadocs):
However, iterators are designed to be used by only one thread at a
time.
That being said, you could also use a CopyOnWriteArrayList, but you have to be careful there, because writes are expensive and the Iterator does not support element changing operations.
Vector clone() is Deep cloning or Shallow cloning?
Clone makes a copy of the references, thus is shallow.
Also pls tell me the significance of Boolean at
ConcurrentHashMap<psConference,Boolean>
The Boolean value is just a placeholder since you are using a Map as a Set. If you look at the source of the Collection class you will see that Boolean.TRUE is always used when adding elements. The actual used container for the Set is the Map#keySet(). So the Boolean parameter does actually nothing here, just a placeholder.
Personally, I would prefer avoiding concurrency problems as much as possible. Could you maybe send an example of code which throws ConcurrentModificationException? There is maybe a way to re-design algorithms to avoid them.
Also, I would rather use ArrayList to replace Vector.
To answer your point (2), based one this explanation, I would say Vector clone() is probably a shallow clone. By the way, they're also saying that it's usually better to avoid using clone() method.
Keep in mind that the Concurrent versions of the collections will not automagically make concurrent bugs go away.
Still, in your case your best bet would be to create concrete wrapper classes that implement the collection interfaces you expect, delegate all of the necessary methods into the wrapped collection, but know the data types used and know how to create copies of themselves.

Do I have to use a thread-safe Map implementation when only reading from it?

If I do the following.
Create a HashMap (in a final field)
Populate HashMap
Wrap HashMap with unmodifiable wrapper Map
Start other threads which will access but not modify the Map
As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.
Is this right?
This is perfectly fine concerning the map itself. But you need to realize the making the map unmodifiable will only make the map itself unmodifiable and not its keys and values. So if you have for example a Map<String, SomeMutableObject> such as Map<String, List<String>>, then threads will still be able to alter the value by for example map.get("foo").add("bar");. To avoid this, you'd like to make the keys/values immutable/unmodifiable as well.
As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.
Yes. Just make sure that the other threads are started in a synchronized manner, i.e. make sure you have a happens-before relation between publishing the map, and starting the threads.
This is discussed in this blog post:
[...] This is how Collections.unmodifiableMap() works.
[...]
Because of the special meaning of the keyword "final", instances of this class can be shared with multiple threads without using any additional synchronization; when another thread calls get() on the instance, it is guaranteed to get the object you put into the map, without doing any additional synchronization. You should probably use something that is thread-safe to perform the handoff between threads (like LinkedBlockingQueue or something), but if you forget to do this, then you still have the guarantee.
In short, no you don't need the map to be thread-safe if the reads are non-destructive and the map reference is safely published to the client.
In the example there are two important happens-before relationships established here. The final-field publication (if and only if the population is done inside the constructor and the reference doesn't leak outside the constructor) and the calls to start the threads.
Anything that modifies the map after these calls wrt the client reading from the map is not safely published.
We have for example a CopyOnWriteMap that has a non-threadsafe map underlying that is copied on each write. This is as fast as possible in situations where there are many more reads than writes (caching configuration data is a good example).
That said, if the intention really is to not change the map, setting an immutable version of the map into the field is always the best way to go as it guarantees the client will see the correct thing.
Lastly, there are some Map implementations that have destructive reads such as a LinkedHashMap with access ordering, or a WeakHashMap where entries can disappear. These types of maps must be accessed serially.
You are correct. There is no need to ensure exclusive access to the data structure by different threads by using mutex'es or otherwise since it's immutable. This usually greatly increases performance.
Also note that if you only wrap the original Map rather than creating a copy, ie the unmodifiable Map delegates method calls further to the inner HashMap, modifying the underlying Map may introduce race condition problems.
Immutable map is born to thread-safe. You could use ImmutableMap of Guava.

Categories