I have an EnumSet which is final and immutable i.e. initialized once in the constructor.
Is the contains() method on this EnumSet thread safe? It is internally using an iterator to make the contains check. Hence if two threads are simultaneously calling the contains() can the iterator position in one call effect other one? Or are the iterators having different instances in these two thread calls?
The contents of an EnumSet can be changed despite the reference to it being final. No EnumSet is immutable. You can, however, wrap your EnumSet via Collections.unmodifiableSet(). If you also avoid retaining any reference to the original EnumSet then the unmodifiable wrapper object is functionally immutable.
Mutability notwithstanding, two iterators operating over the same Set at the same time presents no problem as long as the Set is not modified. This isn't really any different from the case of just one iterator.
In any case, the contains() method of an EnumSet likely doesn't create or use an iterator. The class implements membership via a bit vector, so it uses bit operations to perform the contains() test.
No, if two threads call contains() at the same time, that will call iterator() twice which will create two separate iterators.
If you were trying to share an iterator between two threads, that would not be a good idea.
Note that if you modify the set in one thread while iterating over it (e.g. via contains) in another, then this bit of the docs comes into play:
The returned iterator is weakly consistent: it will never throw ConcurrentModificationException and it may or may not show the effects of any modifications to the set that occur while the iteration is in progress.
Related
HashTable is a thread-safe collection but does initializing it with an ArrayList (which is not thread-safe) as value endanger the whole thread-safety aspect?
Hashtable <Employee, ArrayList<Car>> carDealership = new Hashtable<>();
Further on, I am planning to wrap every action of ArrayLists in a synchronized block to prevent any race-conditions when operating with any methods.
Yet I haven't declared the ArrayLists in the HashTable as synchronized lists, this being achieved with the following code
Collections.synchronizedList(new ArrayList<>())
This will happen when I will be adding ArrayLists to the HashTable obviously.
How can I be sure that the ArrayLists in the HashTable are thread-safe?
Is it enough to pass a thread-safe ArrayList to the put() method of the hashTable and I'm good to go? (and not even worry about the constructor of the HashTable?) Therefore the put() method of the HashTable doesn't even recognize if I am passing a thread-safe/unsafe parameter?
Note: Thread-safety is a requirement. Otherwise I wouldn't have opted for this implementation.
The only way to ensure that the values in the Hashtable or ConcurrentHashMap are thread-safe is to wrap it in a way that prevents anyone from adding something that you don't control. Never expose the Map itself or any of the Lists contained in it to other parts of your code. Provide methods to get snapshot-copies if you need them, provide methods to add values to the lists, but make sure the class wrapping the map is the one that will create all lists that can ever get added to it. Iteration over the "live" lists in you map will require external synchronisation (as metioned in the JavaDocs of synchronizedList).
Both Hashtable and ConcurrentHashMap are thread-safe in that concurrent operations will not leave them in an invalid state. This means e.g. that if you invoke put from two threads with the same key, one of them will return the value the other inserted as the "old" value. But of course you can't tell which will be the first and which will be second in advance without some external synchronization.
The implementation is quite different, though: Hashtable and the synchronized Map returned by Collections.synchronizedMap(new HashMap()); are similar in that they basically add synchronized modifiers to most methods. This can be inefficient if you have lots of threads (i.e. high contention for the locks) that mostly read, but only occasionally modify the map. ConcurrentHashMap provides more fine grained locking:
Retrieval operations (including get) generally do not block
which can yield significantly better performance, depending on your use case. I also provides a richer API with powerful search- and bulk-modification-operations.
Yes, using ArrayList in this case is not thread safe. You can always get the object from the table and operate on it.
CopyOnWriteArrayList is a good substitue for it.
But you still have the case, when one thread takes (saves in a variable) the collection, and the other thread replaces with another one.
If you are not going to replace the lists inside the table, then this is not a problem.
I have a ConcurrentHashMap<String, Object> concurrentMap;
I need to return String[] with keys of the map.
Is the following code:
public String[] listKeys() {
return (String[]) concurrentMap.keySet().toArray();
}
thread safe?
While the ConcurrentHashMap is a thread-safe class, the Iterator that is used on the keys is NOT CERTAIN to be in sync with any subsequent HashMap changes, once created...
From the spec:
public Set<K> keySet()
Returns a Set view of the keys contained in this map......
...........................
The view's iterator is a "weakly consistent" iterator that will
never throw ConcurrentModificationException, and guarantees to
traverse elements as they existed upon construction of the iterator,
and may (but is not guaranteed to) reflect any modifications
subsequent to construction.
Yes and No. Threas-safe is only fuzzily defined as soon as you extend to scope.
Generally, concurrent collections implement all their methods in ways that allow concurrent access by multiple threads, or if they can't, provide mechanisms to serialize such accesses (e.g. synchronization) transparently. Thus, they are safe in the sense they ensure they preserve a valid internal structure and method calls give valid results.
The fuzziness starts if you look at the details, e.g. toArray() will return you some kind of snapshot of the collections contents. There is no guarantee that by the time the method returns the contents will not have already been changed. So while the call is thread safe, the result will not fulfill the usual invariants (e.g. the array contents may not be the same as the collections).
If you need consistency over the scope of mupltiple calls to a concurrent collection, you need to provide mechanisms within the code calling the methods to ensure the required consistency.
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
If I create a single instance of a Comparator, can that instance be used across multiple threads to sort collections using Collections.sort()? Or, do I need to create a new instance of the Comparator for each call to Collections.sort() to ensure thread safety?
That depends entirely on how you implement the Comparator. If, for example, it has instance variables that are written to or whose contents are changed implicitly during comparison, it would not be threadsafe.
Most Comparator implementations do no such thing, but one scenario that might reasonably occur is using a SimpleDateFormat to compare Strings that represent dates. Unfortunately, SimpleDateFormat itself is not thread safe.
Comparator is an interface, it has no inherent concurrency properties. It's up to how you write it if your implementation is threadsafe or not. If everything it does is confined to the scope of the compare method (No Instance or Class level state) and all the resources it uses are threadsafe, then it will itself be threadsafe.
I'd very surprised if I found a non-thread safe Comparator, since they're usually (always?) reentrant.
The concurrency problem would be if the collection being sorted was being changed while the sort happened.
If all attributes (or items fields, or data members) of a java collection are thread-safe (CopyOnWriteArraySet,ConcurrentHashMap, BlockingQueue, ...), can we say that this collection is thread-safe ?
an exemple :
public class AmIThreadSafe {
private CopyOnWriteArraySet thradeSafeAttribute;
public void add(Object o) {
thradeSafeAttribute.add(o);
}
public void clear() {
thradeSafeAttribute.clear();
}
}
in this sample can we say that AmIThreadSafe is thread-safe ?
Assuming by "attributes" you mean "what the collection holds", then no. Just because the Collection holds thread-safe items does not mean that the Collection's implementation implements add(), clear(), remove(), etc., in a thread-safe manner.
Short answer: No.
Slightly longer answer: because add() and clear() are not in any way synchronized, and HashSet isn't itself synchronized, it's possible for multiple threads to be in them at the same time.
Edit following comment: Ah. Now the short answer is Yes, sorta. :)
The reason for the "sorta" (American slang meaning partially, btw) is that it's possible for two operations to be atomically safe, but to be unsafe when used in combination to make a compound operation.
In your given example, where only add() and clear() are supported, this can't happen.
But in a more complete class, where we would have more of the Collection interface, imagine a caller who needs to add an entry to the set iff the set has no more than 100 entries already.
This caller would want to write a method something like this:
void addIfNotOverLimit (AmIThreadSafe set, Object o, int limit) {
if (set.size() < limit) // ## thread-safe call 1
set.add(o); // ## thread-safe call 2
}
The problem is that while each call is itself threadsafe, two threads could be in addIfNotOverLimit (or for that matter, adding through another method altogether), and so threads A would call size() and get 99, and then call add(), but before that happens, it could be interrupted, and thread B could then add an entry, and now the set would be over its limit.
Moral? Compound operations make the definition of 'thread safe' more complex.
No, because the state of an object is the "sum" of all of its attributes.
for instance, you could have 2 thread-safe collections as attributes in your object. additionally, your object could depend on some sort of correlation between these 2 collections (e.g. if an object is in 1 collection, it is in the other collection, and vice versa). simply using 2 thread-safe collections will not ensure that that correlation is true at all points in time. you would need additional concurrency control in your object to ensure that this constraint holds across the 2 collections.
since most non-trivial objects have some type of correlation relationship across their attributes, using thread-safe collections as attributes is not sufficient to make an object thread-safe.
What is thread safety?
Thread safety simply means that the
fields of an object or class always
maintain a valid state, as observed by
other objects and classes, even when
used concurrently by multiple threads.
A thread-safe object is one that
always maintains a valid state, as
observed by other classes and objects,
even in a multithreaded environment.
According to the API documentation, you have to use this function to ensure thread-safety:
synchronizedCollection(Collection c)
Returns a synchronized (thread-safe) collection
backed by the specified collection
Reading that, it is my opinion that you have to use the above function to ensure a thread-safe Collection. However, you do not have to use them for all Collections and there are faster Collections that are thread-safe such as ConcurrentHashMap. The underlying nature of CopyOnWriteArraySet ensures thread-safe operations.