How to simulate ConcurrentModificationException in own class? - java

I have been reading "Effective Java" Item 60, which is "Favor the use of standard exceptions".
Another general-purpose exception worth knowing about is ConcurrentModificationException. This exception should be thrown if an object that was designed for use by a single thread or with external synchronization detects that it is being concurrently modified.
Normally people face with CME when they try remove from a collection while looping.
But in here I am interested about what would be a concise example on detecting a concurrent modification on self-implemented class object?
I expect it to be something like synchronizing on internal object and related boolean flag, if another thread confronts the flag being false, then throwing exception.
For a simple research I have found in source of ArrayList:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
but the principle behind how modCount is maintained. I cannot find where it is being decremented.

The modification count is essentially the "revision number" of the collection's state. It is incremented every time there is a structural change to the collection. It is never decremented.
When starting iteration, the iterator remembers the value of the mod count. It then periodically checks that the container's current mod count still equals the remembered value. If it doesn't -- meaning there has been a structural change since iteration began -- a ConcurrentModificationException is thrown.

As for how you would implement this kind of behaviour yourself: Your class depends on some assumptions to work properly, which could be violated if access to an object is not synchronized properly. Try to check those assumptions and throw a CME if you find that they are not true.
In the example of ArrayList, the assumption is that nobody will change the structure of the list while you are iterating over it, so ArrayList keeps track of a modification count that is not supposed to change during an iteration.
However, this checking is only there to make it more likely that a bad access will cause a clean exception instead of weird behaviour - in other words, this exception is just a help to developers and does not need to enforce correctness, because correctness is already compromised when you encounter it.
It is a good idea to offer this kind of help where it does not impact the performance of your class much, but using e.g. synchronization to ensure correct use is probably a bad idea - then you might as well make the class threadsafe to begin with.
This is why the API documentation for ArrayList says:
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throw ConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.

So, the general approach is following: just remember current state of your object and check its state every time when trying to access the object, if state changed, throw your exception!

Related

Is modCount an atomic variable?

I read that a ConcurrentModificationException can be thrown whenever a thread performs a structural modification upon a certain list while another thread is iterating over its elements. To detect such modification, instances of the class List store the number of times they were modified in a field called modCount, whose value is checked at each iteration of the list to check whether the latter was modified. If my understanding was correct, access to modCount needs to be synchronized, because if the list in question was to be modified after checking the value of modCount in the last iteration and before the end of the loop, the iterator would fail to detect that the list was modified during its last iteration.
Everything you've said is correct, and perfectly normal. modCount is not atomic, and the iterator could fail to detect that the list was modified, and that's fine. Revisit the ArrayList documentation:
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Because ArrayList does not try to guarantee that it will always detect a concurrent modification, it can avoid the overhead of an atomic variable for a case that should never happen in correct code. The use of the unsynchronized modCount detects the most common cases, and will sometimes (depending on exact thread ordering and the like) detect cases that are truly concurrent. Remember, though, that ConcurrentModificationException almost never happens because concurrency is actually going on, but because someone calls a modification method during an iteration loop.

Can Collection.size() throw ConcurrentModificationException?

As we all know, iterating without synchronization on a collection risks throwing ConcurrentModificationException if another thread happens to concurrently modify the collection.
But what about calling size() on the collection? Does size() involve iteration to count the number of elements in the collection? If that is the case, ConcurrentModificationException may occur (some people report this, for example here, but for me it is not clear that size() was the culprit).
On the other hand, if size() just gets an internal int counter variable, no exception would occur.
Which one is the case?
HUMBLE EDIT: Thanks to the answerers for the precision that this depends on the implementation. I should have mentioned that it is a TreeMap. Can I have this problem with that map? The docs say nothing about TreeMap.size().
The docs don't explicitly state that a ConcurrentModificationException will occur if you invoke Collection#size.
The only real times it's thrown are described in ConcurrentModificationException itself:
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
If you're really worried about this sort of thing, then be sure that the concrete implementation of your collection uses an approriate size() method, like ConcurrentLinkedQueue.
Returns the number of elements in this queue. If this queue contains more than Integer.MAX_VALUE elements, returns Integer.MAX_VALUE.
Beware that, unlike in most collections, this method is NOT a constant-time operation. Because of the asynchronous nature of these queues, determining the current number of elements requires an O(n) traversal.
Additionally, if elements are added or removed during execution of this method, the returned result may be inaccurate. Thus, this method is typically not very useful in concurrent applications.
It doesn't matter whether size() will throw ConcurrentModificationException. Almost no collections will throw that exception on size(), but that doesn't make it safe.
When you call size() on a collection that other threads modify, you're reading shared memory. If the collection you're using doesn't offer specific synchronization guarantees and you're not using other synchronization mechanisms, the value you read could be arbitrarily out of date, or it could even correspond to a program state that you would think "hasn't happened yet".

Why Iterators fail fast and are they truly fail fast?

Iterators in Java are fail-fast. If an iterator values change while it is being iterated over, an exception is thrown.
Is this purely to be safe? I am sure that in some cases, it doesn't matter that much if the values change. For example, suppose you were sending non critical alerts to members in an iterator every 10 seconds - why would you care if the contents is changed?
Also, the fail-fast implementation just checks the count. This is flawed in case another thread adds and removes the count will be the same even though the iterator's contents is changed. Would be not be better to use a version number?
The fail-fast behavior is purely to aid debugging. The general rule is that if you modify a collection while iterating over it through some means other than the iterator's members, the behavior of the iterator is no longer predictable. It will throw an exception on a best-effort basis.
As such, any method of tracking that is expensive is a bad idea.

How do fail-fast Iterators come to know that underlying structure is modified when the throws 'ConcurrentModificationException' is thrown?

Fail-fast Iterators fail as soon as they realized that structure of Collection has been changed since iteration has begun. Structural changes means adding, removing or updating any element from collection while one thread is Iterating over that collection.
But how does it come to know the change ?
Just checked the source code for the HashMap class. In particular search for 'modCount'. The private HashIterator class, for example, keeps a count of the number of times an instance has been modified (except using the 'remove' method) since the instance was created.
For the 'nextEntry' method the count is checked to see if it has changed and may throw that exception. The 'remove' method also checks the count but, if successful, resets the count to the new value. It does this so that you can use the 'remove' method to remove an entry WITHOUT getting the exception.
Other methods (e.g. 'clear') will increment the 'modCount'. As the above code excerpt shows that will cause the exception to be raised the next call of 'nextEntry'.
There are NO guarantees that the exception will be thrown.
The API:
http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html
Note that fail-fast behavior cannot be guaranteed as it is, generally
speaking, impossible to make any hard guarantees in the presence of
unsynchronized concurrent modification. Fail-fast operations throw
ConcurrentModificationException on a best-effort basis. Therefore, it
would be wrong to write a program that depended on this exception for
its correctness: ConcurrentModificationException should be used only
to detect bugs.

How to Redesigning a method in order for it to work

My code results in an java.util.ConcurrentModificationException error. Here is the following code.
Here is the exact error:
java.util.ConcurrentModificationException
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:894)
at java.util.HashMap$KeyIterator.next(HashMap.java:928)
at ca.on.oicr.pinery.lims.gsle.GsleClient.getOrders(GsleClient.java:720)
Line 720 is the second for loop
I posted this question before and was told that "You're adding to orders inside a loop that's looping over the elements of orders, that's what causes the exception. Don't modify a collection you're looping over inside the loop. Likewise with samples". I understand that I to re construct this method and received the following suggestions.
ListIterator<Order> it = orders.listIterator();
while ( it.hasNext() ) {
Order ord = it.next();
if ( ) // some condition
it.remove(); // This wil remove the element that we just got using the next() method
if ( ) // some other condition
it.add(new Order()); // THis inserts the element immediately before the next call to next()
}
Now I am stuck at how to do the adding of the samples and the order when using the iteration method since you would iterate differently though a set, I assume I would use a for loop.
This is the part I am getting confused on how to change in order to not get the java.util.ConcurrentModificationException.
f
So far I have gotten up to here.
java.util.ListIterator<Order> it = orders.listIterator();
while (it.hasNext()) {
it.next().getId();
if (sampleOrderMap.containsKey((it.next().getId())))
{
Set<OrderSample> samples = sampleOrderMap.get(it.next().getId());
}
}`
I just do not know how to put in the rest in a way that I would not get the ConcurrentModificationException
From Java Docs:
ConcurrentModificationException may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
To go around this, you can create a temporary collection to add to other than the one you are iterating through.
Then, after you finish iterating, you can use orders.AddAll(tempCollection) to add the new items.

Categories

Resources