Why does one loop throw a ConcurrentModificationException, while the other doesn't? - java

I've run into this while writing a Traveling Salesman program. For an inner loop, I tried a
for(Point x:ArrayList<Point>) {
// modify the iterator
}
but when adding another point to that list resulted in a ConcurrentModicationException being thrown.
However, when I changed the loop to
for(int x=0; x<ArrayList<Point>.size(); x++) {
// modify the array
}
the loop ran fine without throwing an exception.
Both a for loops, so why does one throw an exception while the other does not?

As others explained, the iterator detects modifications to the underlying collection, and that is a good thing since it is likely to cause unexpected behaviour.
Imagine this iterator-free code which modifies the collection:
for (int x = 0; list.size(); x++)
{
obj = list.get(x);
if (obj.isExpired())
{
list.remove(obj);
// Oops! list.get(x) now points to some other object so if I
// increase x again before checking that object I will have
// skipped one item in the list
}
}

The first example uses an iterator, the second does not. It is the iterator that checks for concurrent modification.

the first code is using an iterator so modifying the collection is not allowed. The second code you are accessing each object with x.get(i), so not using an iterator, modifications thus are allowed

You cannot modify a List while you are iterating over it which you are doing in the first example. In the second you simply have a regular for loop.

If you run the code and observe you find that first iteration of the loop works fine but the second throws ConcurrentModicationException
if is because next() method checks if the number of the elements did not change.
For nice explanation see http://javaadami.blogspot.com/2007/09/enhanced-for-loop-and.html

Related

Iterating over ConcurrentSkipListSet with different thread removing elements

I have a ConcurrentSKipListSet, and I'm iterating over values in this set with a for-each loop.
Another thread at some point is going to remove an element from this set.
I think I'm running into a situation where one thread removes an element that I'm yet to iterate over (or maybe I've just started to iterate over it) and so a call being made from within the loop fails.
Some code for clarity:
for(Foo foo : fooSet) {
//do stuff
//At this point in time, another thread removes this element from the set
//do some more stuff
callService(foo.getId()); // Fails
}
Reading the docs I can't work out if this is possible or not:
Iterators are weakly consistent, returning elements reflecting the state of the set at some point at or since the creation of the iterator. They do not throw ConcurrentModificationException, and may proceed concurrently with other operations.
So is this possible, and if so, what's a good way of handling this?
Thanks
Will
I think I'm running into a situation where one thread removes an element that I'm yet to iterate over (or maybe I've just started to iterate over it) and so a call being made from within the loop fails.
I don't think that's what the javadocs are saying:
Iterators are weakly consistent, returning elements reflecting the state of the set at some point at or since the creation of the iterator. They do not throw ConcurrentModificationException, and may proceed concurrently with other operations.
This is saying that you don't have to worry about someone removing from the ConcurrentSkipListSet at the same time that you are iterating across the list. There certainly is going to be a race condition as you are moving across the iterator however. Either foo gets removed right after your iterator gets it or it was removed right before and the iterator doesn't see it.
callService(foo.getId()); // this shouldn't "fail"
If foo gets returned by the iterator, your service call won't "fail" unless it is assuming that the foo is still in the list and somehow checking it. The worst case is that you might do some operations on foo and call the service with it even though it was just removed from the list by the other thread.
I've hit this problem as well with queues that are written to and read by different threads. One approach is to mark instead of remove elements that are no longer needed. You can run a cleanup iterator after you go through the whole list. You need a global lock just for removing elements from the list, and the rest of the time your code can run in parallel. Schematically it works like this:
writer:
while() {
set.add(something);
something.markForDelete();
}
reader:
while() {
// process async
iterator iter = set.getIterator();
for(iter.hasNext()) {
... work, check isMarkedForDelete() ...
}
iter = set.getIterator();
// delete, sync
globalLock.Lock();
for(iter.hasNext()) {
if(something.isMarkedForDelete()) {
set.remove(something);
}
globalLock.Unlock();
}
}

using if statement within while breaks the loop in Java

I am new in Java and I have a problem in using if statement within while loop.
I wrote the code as follows:
while(lexicalizations.hasNext())
{
myObject = lexicalizations.next().getObject();
language= myObject.getTermLanguage();
if (language.equals(languageCode)) {
System.out.println(lexicalizations.next());
}
}
However, whenever the if condition is true, the program executes its block and then terminates the while loop. So, the rest of items are not checked out.
How could I solve that?
Thanks so much.
Cheers,
Aya.
Each invocation of Iterator.next() moves the iterator to the next element of the collection, therefore you must be very careful not to call this method more than once per iteration. You must save the element into a local variable and work with the variable throughout the loop body.
In order to systematically avoid this kind of pitfalls, always prefer to use the enhanced for loop whenever applicable:
for (String lex : lexicalizations) {
... your code uses lex here ...
}
Note that when you do that println you "consume" the next element, so if there is only one left there will be zero when you get back to the while.
You are moving to the next object in the iterator within if statement block. To avoid this just use myObject and you will 'visit' every object:
while (lexicalizations.hasNext())
{
myObject = lexicalizations.next().getObject();
language= myObject.getTermLanguage();
if (language.equals(languageCode)) {
System.out.println(myObject);
}
}

another ConcurrentModificationException

I am new to Java and especially to iterating through lists and modifying it's elements. I went through dozens of similar questions, but after many tries nothing worked.
In the following code sample an exceptions is thrown. It is not related to concurrent thread as I only have one thread. Netbeans output sais that the exception occurs in line 5(CustomerData customer = i.next();) :
CustomerData tempCustomer = new CustomerData("",tagID,0);
tempCustomer.setName(name);
tempCustomer.setSize(size);
for(ListIterator<CustomerData> i = customers.listIterator(); i.hasNext(); )
{
CustomerData customer = i.next();
if(customer.getTagID().contains(tagID))
{
Object[] options = {"overwrite", "do not overwrite"};
int n = JOptionPane.showOptionDialog(rootPane,
"TagID already exists. overwrite?",
"?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
rootPane);
if ( n == JOptionPane.YES_OPTION ){
i.set(tempCustomer);
}
}
else{
addCustomer();
}
}
The whole code is only supposed to check if the element has matching tagID and if it does, replace two values (name and size) in it. Initially I tried to use setName() and setSize() inside the for loop on the element, but after it didn't work and after reading other related questions, I assigned the values to temporary object before the loop and the used the iterator's set method to replace current element. But still no success and it even seems it never gets that far because the exception comes after line 5...
The problem is presumably that this line:
addCustomer();
is trying to modify customers while you're in the middle of iterating over it. This isn't allowed.
And anyway, it seems like a logic error: presumably you want to call addCustomer only once, after the loop, if no customer had the right tagID, but your current code tries to call addCustomer for each customer with with the wrong tagID. So you need to use a boolean variable during the loop to keep track of whether any customer matched, and then, after the loop, call addCustomer if appropriate.
ConcurentModificationException does not always indicate that an object has been concurrently modified by a different thread.
In your case the problem might be in following (guessing by addCustomer method): you are getting iterator of collection and then modifiying this collection. Because collection is modified, iterator becomes invalid and exception is thrown.
My suggestion will be create temproray list of customers which will you will append to your original customer list, when your iteration finished.
As mentioned in javadocs:
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.
I guess it is occurring after a call to addCustomer() which modifies the customers object. You can either hold the newly added objects in a different collection until end of the loop or break out of the loop and restart after adding.

Is the loop condition calculated each loop for "for" sentence in Java?

This is my Java code:
List<Object> objects = new ArrayList();
// Assign values to objects
...
for (int i = 0; i < objects.size(); i++) {
Object object = objects.get(i);
...
}
I have two questions:
Is objects.size() calculated only once before stating the loop, or is it calculated each loop?
If objects.size() is calculated each loop, then if other thread change it at the same time without multi-threads protection, the code may be crashed.
Am I correct?
Answers:
objects.size() is called every loop (whether it is calculated depends on the ArrayList implementation, which you shouldn't care about)
Yes, another thread may change the list and this will affect your loop
Real answer:
You shouldn't have to care, and here's how you don't have to:
Use a CopyOnWriteArrayList, which is thread-safe. If you iterate over it using an Iterator (as the foreach syntax uses internally), you'll iterate over the list as it was when the iteration started
Use the foreach syntax, which means you don't have to use an index etc - it's done for you:
for (Object object : objects) {
// do something with each object
}
Yes, it is calculated each time. If you have another thread altering the size of your objects list, the loop condition will keep changing.
yes when you are using objects.size() inside the loop condition it calculates every time. better way is to keep it in a variable before going into loop;
like int
limit=objects.size();
for (int i = 0; i < limit; i++) {
Object object = objects.get(i);
...
}
If you have another thread it may change it but using the above option it will not affect or crash you programm.
yes , it will calculate each time
if you look into for loop statement, in the first statement it will set counter initial value
then it will check for maximum value then it will execute for loop body then after it will increase value of counter and then again check for maximum value. every time to check maximum value it will call size method.
Is objects.size() calculated only once before stating the loop, or is it calculated each loop?
Each time.
If objects.size() is calculated each loop, then if other thread change it at the same time without multi-threads protection, the code may be crashed.
Yes. Or at least, you may get a ConcurrentModificationException, and not have any reasonable way to deal with it.
Please note that this could happen even if you cached objects.size(), except now the .get() will fail instead because you are trying to get an index that no longer exists. objects.size() changes because something is removed from, or added to, the container.
Don't modify collections while you are iterating over them.
Notionally the objects.size() could be evaluated on each loop. However, as the method is short it can be inlined and cached as its not a volatile variable. i.e. another thread could change it but there is no guarantee that if it did you would see the change.
A short way to save the size is to use the follow.
for (int i = 0, size = objects.size(); i < size; i++) {
Object object = objects.get(i);
...
}
However if you are concerned that another thread could change the size, this approach only protects you if an object is added. If an object is removed you can still get an exception when you attempt to access the value which is now beyond the end of the list.
Using a CopyOnWriteArrayList avoids these issues (provided you use an Iterator) but makes writes more expensive.

Java - Difference between for loop terminating expression

I'm just curious: Is there a difference on speed and performance between this two loops implementation? Assume that size() method returns the length of the array,collection, or object that handles a group of elements (actually it's from XOM api).
Implementation 1:
int size = someArray.size();
for (int i = 0; i < size; i++) {
// do stuff here
}
Implementation 2:
for (int i = 0; i < someArray.size(); i++) {
// do stuff here
}
From a performance point of view, there is little difference. This is because a loop can be optimized so that the size() lookup is inlined, resulting in very little performance difference.
The main difference is if the size changes while looping. The first case will try to iterate a fixed number of times. In the second case, the number of iterations will depend on the final size().
The 1st snippet is bound to execute faster since it calls size() once only. The 2nd snippet calls size() N times. Depending on the impl. it might pose significant penalty, esp. if the compiler finds hard to inline the method and/or the size() method doesn't just return non-volatile variable, etc.
I'd have rewritten it like for(int i=0, s=someCollection.size(); i<s; i++)
Note: arrays don't have size() method.
Yes, there is a difference. In the first loop, the size() method is only called once. In the second one, it's called at each iteration.
If the iteration modifies the size of the collection (which is very very uncommon), the second one is needed. In most cases, you should prefer the first one, but limit the scope of the size variable :
for (int i = 0, size = someArray.size(); i < size; i++) {
// ...
}
But most of the time, you should prefer the foreach syntax anyway :
for (Foo foo : collection) {
// ...
}
which will iterate over the array or collection efficiently, even for a LinkedList for example, where indexed access is not optimal.
Don't worry about it, JVM optimization is very aggressive these days.
Use the 2nd form, for it's more readable, and most likely as fast. Premature optimization yada yada.
And when you do need to improve speed, always profile first, don't guess.
It is extremely unlikely that caching size() in a local variable could benefit your app noticeably. If it does, you must be doing simple operations over a huge dataset. You shouldn't use ArrayList at all in that case.
Maybe it is worth to note that this construct:
for (String s : getStringsList()) {
//...
}
invokes getStringsList() only once and then operates on iterator behind the scenes. So it is safe to perform lengthy operations or change some state inside getStringsList().
Always avoid anything that can be done outside of the loop like method calls, assigning values to variables, or testing for conditions.
Method calls are more costly than the equivalent code without the call, and by repeating method calls again and again, you just add overhead to your application.
Move any method calls out of the loop, even if this requires rewriting of the code.
Benefits :-
Unless the compiler optimizes it, the loop condition will be calculated for each iteration over the loop.
If the condition value is not going to change, the code will execute faster if the method call is moved out of the loop.
Note :-
If the method returns a value that will not change during the loop, then store its value in a temporary variable before the loop.
Hence its value is stored in a temporary variable size outside the loop, and then used as the loop termination condition.

Categories