• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Single thread - ConcurrentModificationException - java.util.ArrayDeque method addFirst()

 
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys, wondering if anyone could shed some light on this. ArrayDeque's iterator is fail-fast. Here is a simple example of the collection being amended after an iterator is created. This code throws a ConcurrentModificationException when I try to use the iterator after I call add(E e) OR addLast(E e) but NOT when I call addFirst(E e). Any idea why this is ? Is addFirst(E e) not considered to be a structural alteration to the collection ?

UPDATE : In fact none of the methods addFirst, offerFirst, removeFirst, pollFirst result in a subsequent throw of ConcurrentModificationException when the iterator's next() method is called (compared with a call to equivalent somethingLast methods which do result in a throw of ConcurrentModificationException when the iterator's next() method is called) ?

 
Bartender
Posts: 242
27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Think of it from the perspective of the Iterator. Initially without modification, we have this:

one (<- next)

This is how the iterator expects it to be for the rest of the iteration. Now add an element onto the end:

one (<- next)
two

This is bad because we have changed the data that iterator will receive. Two wasn't in there when it was created, but it is now. Now, how about with addFirst?

two
one (<- next)

addFirst adds it before everything else, but the next is already pointed to one. This doesn't actually change the data that the iterator will return, it will all be the same regardless of what you addFirst. Even though you did change the deque, it's the same from the iterators perspective.


Now: try it with a descendingIterator and watch it work exactly the opposite:
 
John Mulholland
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Zachary - I had previously thought that, on construction, an iterator would have some kind of cursor pointing to a position BEFORE the first element, and that the first call to next() would move the cursor to the first element (and return that element). But I think you're saying that the iterator ALREADY points to the first element as soon as it is constructed. On that basis, I can see why using addFirst() would not interfere with the iterator (unless, as you say, it was a descendingIterator).

Many thanks for your help
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes... your theory was a plausible one, but it's been proven false by the example you posted. The class could have been designed according to that theory, I think, but apparently it wasn't. An arbitrary implementation detail? It may be that the designers of the class discussed this particular example, but we'll never know for sure. Unless some other evidence shows up, like comments in the source code or somebody's blog posts.
 
Sheriff
Posts: 22783
131
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The javadoc of ArrayDeque is actually not in sync with its own implementation (found in src.zip inside the JDK's root folder). The javadoc says that any modifying operation (so including addFirst and addLast) should cause a ConcurrentModificationException in the iterator, without exceptions. However, the normal iterator only checks for the tail (end), and the descending iterator only checks for the head (start). addLast only modifies the tail* and addFirst only modifies the head*, so the behavior you see matches the code - addFirst does not cause ConcurrentModificationExceptions when iterating forward, and addLast does not cause ConcurrentModificationExceptions when iterating backward.

Anybody feel like posting a bug at Oracle, to either fix the javadoc or the implementation?


* unless if the ArrayDeque's capacity needs to be increased.
 
John Mulholland
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Rob (and Paul) .. I've never posted bug with Oracle before but would be happy to give it a try to see how it's done.
 
Zachary Griggs
Bartender
Posts: 242
27
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is a comment from the java code

So it sounds like they know about it, but just don't care.
 
Paul Clapham
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

John Mulholland wrote:Hi Rob (and Paul) .. I've never posted bug with Oracle before but would be happy to give it a try to see how it's done.



Looks like this is the place to go for that: http://bugreport.java.com/

I suspect that documentation bugs are going to take a back seat to code which is broken in some way, but it's still worth putting this bug into the system.
 
Greenhorn
Posts: 12
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

John Mulholland wrote:Hi guys, wondering if anyone could shed some light on this. ArrayDeque's iterator is fail-fast. Here is a simple example of the collection being amended after an iterator is created. This code throws a ConcurrentModificationException when I try to use the iterator after I call add(E e) OR addLast(E e) but NOT when I call addFirst(E e). Any idea why this is ? Is addFirst(E e) not considered to be a structural alteration to the collection ?

UPDATE : In fact none of the methods addFirst, offerFirst, removeFirst, pollFirst result in a subsequent throw of ConcurrentModificationException when the iterator's next() method is called (compared with a call to equivalent somethingLast methods which do result in a throw of ConcurrentModificationException when the iterator's next() method is called) ?



If you are asking about the logic, I would say it's just the expected behavior of 'DeqIterator'. You can see when constructing the iterator, it will pass the current ArrayDeque's 'tail' to the attribute 'fence' of 'DeqIterator', but everytime you call 'addLast', it will increase the tail by one, and the exception will be thrown if 'tail != fence'.
 
We can fix it! We just need some baling wire, some WD-40, a bit of duct tape and this tiny ad:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic