Concurrency on Treeset using last method - java

I want to implement a bean where I have a TreeSet that is storing integers in sorted order. The only methods that use this TreeSet are addValue that is adding a new integer to the set, and getHighestValue that is returning the last value in the set using the method last() from SortedSet.
Is there any concurrency issue here? I'm not using any explicit iterator so there shouldn't be any concurrency problem when fetching the highest value but I don't know if last method can throw any ConcurrentModificationException or any other exception if two threads try to add and get the highest value at the same time.

Yes, assuming multiple threads are interacting with the set, and at least one is modifying, there are concurrency concerns. In particular, you mention multiple threads doing the add operation, which is definitely going to cause problems - worse however, they may not raise ConcurrentModificationExceptions.
The purpose of ConcurrentModificationException is to alert you to clearly erroneous concurrency issues, such as attempting to remove an item from a collection as you iterate over it (it's unclear what the collection should even do, in such a case). However the exception can only be raised when the collection is aware of the erroneous modification. Since the collection is not thread-safe it explicitly does not guarantee multi-threaded operations will be done correctly, and you are expected to take care of explicitly protecting the collection yourself.
The easiest, though least efficient, way to do this is to wrap the set with Collections.synchronizedSortedSet() before using it, i.e.:
SortedSet synchronizedSet = Collections.synchronizedSortedSet(new TreeSet());
This ensures that each method call will be done in serial, that is to say they will block waiting for any earlier calls to finish. However as such, you essentially lose most of the benefits of multi-threading.
Another alternative is to use an explicitly thread-safe SortedSet, namely ConcurrentSkipListSet:
This implementation provides expected average log(n) time cost for the contains, add, and remove operations and their variants. Insertion, removal, and access operations safely execute concurrently by multiple threads.
This implementation allows you to interact with the set from multiple threads without further concern. That isn't to say it is the best way to implement the behavior you're looking for, but given what you've described - add and access the maximum value in a sorted set from multiple threads - it's what you're looking for.
See also: When is a ConcurrentSkipListSet useful?

Related

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

Is there a way to opt for "unspecified behavior" rather than ConcurrentModificationException?

I know that code like
for ( Object o: collection){
if (condition(i)){
collection.remove(i);
}
}
will throw a ConcurrentModificationException, and I understand why: modifying the collection directly could interfere with the Iterator's ability to keep track of its place, by, for instance, leaving it with a reference to an element that's no longer a part of the collection, or causing it to skip over one that's just been added. For code like the above, that's a reasonable concern, however, I would like to write something like
for (Object o: set){// set is an instance of java.util.LinkedHashSet
if (condition(o)){
set.remove(other(o));
}
}
Where other(o) is guaranteed to be "far" from o in the ordering of set. In my particular implementation it will never be less than 47 "steps" away from o. Additionally, if if condition(o) is true, the loop in question will be guaranteed to short-circuit well before it reaches the place where other(o) was. Thus the entire portion of the set accessed by the iterator is thoroughly decoupled from the portion that is modified. Furthermore, the particular strengths of LinkedHashSet (fast random-access insertion and removal, guaranteed iteration order) seem particularly well-suited to this exact sort of operation.
I suppose my question is twofold: First of all, is such an operation still dangerous given the above constraints? The only way that I can think that it might be is that the Iterator values are preloaded far in advance and cached, which I suppose would improve performance in many applications, but seems like it would also reduce it in many others, and therefore be a strange choice for a general-purpose class from java.util. But perhaps I'm wrong about that. When it comes to things like caching, my intuition about efficiency is often suspect. Secondly, assuming this sort of thing is, at least in theory, safe, is there a way, short of completely re-implementing LinkedHashSet, or sacrificing efficiency, to achieve this operation? Can I tell Collections to ignore the fact that I'm modifying a different part of the Set, and just go about its business as usual? My current work-around is to add elements to an intermediate collection first, then add them to the main set once the loop is complete, but this is inefficient, since it has to add the values twice.
The ConcurrentModificationException is thrown because your collection may not be able to handle the removal (or addition) at all times. For example, what if the removal you performed meant that your LinkedHashSet had to reduce/increase the space the underlying HashMap takes under the hood? It would have to make a lot of changes, which would possibly render the iterator useless.
You have two options:
Use Iterator to iterate elements and remove them, e.g. calling Iterator iter = linkedHashSet.iterator() to get the iterator and then remove elements by iter.remove()
Use one of the concurrent collections available under the java.util.concurrent package, which are designed to allow concurrent modifications
This question contains nice details on using Iterator
UPDATE after comments:
You can use the following pattern in order to remove the elements you wish without causing a ConcurrentModificationException: gather the elements you wish to remove in a List while looping through the LinkedHashSet elements. Afterwards, loop through each toBeDeleted element in the list and remove it from the LinkedHashSet.

Is CopyOnWriteArrayList enough for keeping shopping cart thread-safe in Servlet Session scope

Is CopyOnWriteArrayList list enough to use as a collection for shopping-cart. As I understand it is thread-safe and the iterator is guaranteed not to throw ConcurrentModificationException when during iteration another thread removes a product. For example:
...
CopyOnWriteArrayList<Product> products = (CopyOnWriteArrayList<Product>)session.getAttribute("PRODUCTS");
products.addIfAbsent(aProduct);
...
P.S. I found synchronization approaches using synchronized (session) {...} but it seams a little ugly when I need synchronize session access everywhere when I work with shopping-cart as offered in this article
You need to understand what CopyOnWriteArrayList provides.
It provides you a snapshot and does not give you real time view of backend array.
It weakens the contract of visibility, it says that you will not get ConcurrentModificationException but also says that if other thread removes some element, the effect will not be visible to other thread which is iterating maybe, because on addition or removal the original array is not mutated or touched and a new one is created on every operation that mutates the backing array.
Is CopyOnWriteArrayList list enough to use as a collection for
shopping-cart.
Depends.
If this behavior is acceptable in your scenario then you can use it, but if you want visibility guarantee you may have to use explicit locking.
I think you are good to go with CopyOnWriteArrayList in the scenario you described.
It has sufficient guarantees to work as thread safe Implementations including
visibility. Yes it is true that it gives the snapshot of the data when you call iterate.
But there is always a race condition, while you remove it before reading or read it before removing.CopyOnWriteArrayList is a fine implementation
which can be used where reads >>> writes, which i think is the case in shopping cart use case.
It is just that while iterating you will not see changes (write operation). You should understand nothing is free, if you want to see the changes while traversing you need to properly synchronize your every iteration with any write operation which is will compromise perfomance. Trust me you will gain nothing. Most of the concurrent Data structures gives weakly consistent state on iteration see (ConcurrentSkipListSet).
So use either CopyOnWriteArrayList, ConcurrentSkipListSet you are good to go.
I think sets are better for your use case i.e to avoid duplicate orders ..
Is CopyOnWriteArrayList list enough to use as a collection for shopping-cart
No because it depends on what you need to synchronize. Think about what must not happen at the same time.
As I understand it is thread-safe and the iterator is guaranteed not to throw ConcurrentModificationException when during iteration another thread removes a product.
You will not get a ConcurrentModificationException because every modification you do to the list will create a copy of the list. A thread that iterates will use the most current copy. But that thread can't assume that a product is still actually in the list when it sees it. It might have been removed in the most current version.
Or maybe to use "heavier artillery" like following, in all places when accessing to shopping-cart collection.
AtomicReference<List<Product>> productListRef =
AtomicReference<List<Product>>)session.getAttribute("PRODUCTS");
List<Product> oldList;
List<Product> newList;
do {
oldList = productListRef.get();
newList = new ArrayList<>(oldList);
newList.add(aProduct);
} while (!ref.compareAndSet(oldList, newList));
Thank a lot for previous answers!

why java language forbid program update a collection when program iterate it?

I know there is a InnerClass named"Itr" in java.util.AbstractList. and there is a field named "expectedModCount", a method named "checkForComodification". when iterator a collection but update the collection, this method will throw the ConcurrentModificationException
I want to know why java language designed like this? what is the purpose to do like this.
Thx !
I want to know why java language designed like this?
It's not part of the language. It's part of the collection framework.
Basically, it's relatively hard to make a very general specification about what should happen if you're iterating over a collection and it changes underneath you. While you could certainly decide on some rules for a list, what about (say) the entry set for a map? Adding or removing entries could change the internal order entirely - what would you want to happen then?
If it was allowed to change the collection you get a lot of problematic casses.
Say we have a list with elements 0 to 4
the iterator is just passed 3
|0|1|2|3|4|
iterator^
now we add an element at the begining
|5|0|1|2|3|4|
iterator^?^
What should the iterator return now?
it could return 4 since that was the next element before the change
it could return 3 since that is now at the index where the iterator was pointing at
Depending on the list implementation each of these also adds complexity and has a performance penalty, by forbidding the modification of collections we can avoid the specifying a correct behavior and the attached complexity.
You can iterate over a collection and modify it using Iterator (which is the standard way to do this).
See Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop for more discussion around this.
If a collection is modified by one thread while another reads from it, there might happen what we call a Race Condition . Avoiding it costs some performance, but you avoid unpredictable/unwanted results (e.g. you might skip or read twice an existing element in an ArrayList if there was no such check).

is there any Concurrent LinkedHashSet in JDK6.0 or other libraries?

my code throw follow exception:
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
at java.util.LinkedHashSet.<init>(LinkedHashSet.java:152)
...
I want a ConcurrentLinkedHashSet to fix it,
but I only found ConcurrentSkipListSet in java.util.concurrent,this is TreeSet, not LinkedHashSet
any easies way to get ConcurrentLinkedHashSet in JDK6.0?
thanks for help :)
A ConcurrentModificationException has nothing to do with concurrency in the form you're thinking of. This just means that while iterating over the Collection, someone (probably your own code - that happens often enough ;) ) is changing it, i.e. adding/removing some values.
Make sure you're using the Iterator to remove values from the collection and not the collection itself.
Edit: If really another thread is accessing the Collection at the same time, the weak synchronization you get from the standard library is useless anyhow, since you've got to block the Collection for the whole duration of the operation not just for one add/remove! I.e. something like
synchronize(collection) {
// do stuff here
}
You can always create a synchronized collection with Collections.synchronizedMap(myMap);. However, trying to alter the map while you're iterating (which I'm assuming is the cause of your error) will still be a problem.
From the docs for synchronizedMap:
Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee serial access, it is critical that all access to the backing map is accomplished through the returned map.
It is imperative that the user
manually synchronize on the returned
map when iterating over any of its
collection views ... Failure to follow
this advice may result in
non-deterministic behavior.
This is because
normally a concurrent collection is really guaranteeing atomic get/put but is not locking the entire collection during iteration, which would be too slow. There's no concurrency guarantee over iteration, which is actually many operations against the map.
it's not really concurrency if you're altering during iteration, as it's impossible to determine correct behavior - for example, how do you reconcile your iterator returning hasNext == true with deleting a (possibly the next value) from the collection?
There is ConcurrentLinkedHashMap - https://code.google.com/p/concurrentlinkedhashmap/
You can create Set out of it with java.util.Collections.newSetFromMap(map)
Unfortunately not. You could implement your own, wrapping a ConcurrentHashMap and a ConcurrentLinkedQueue, but this wouldn't allow you to remove values easily (removal would be O(N), since you'd have to iterate through everything in the queue) ...
What are you using the LinkedHashSet for though? Might be able to suggest alternatives...

Categories