Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: ConcurrentModificationException in single-threaded context

11 views
Skip to first unread message
Message has been deleted

Lew

unread,
Jul 23, 2008, 1:14:16 PM7/23/08
to
On Jul 23, 12:35 pm, laurens.vanh...@telenet.be wrote:
> Got a weird CME when doing Map.puts or Map.gets on a private HashMap
> which gets accessed by a SINGLE thread. I also never extract iterators
> from the Map.. I only do put() and get().. yet sometimes I get
> ConcurrentModificationException. Toggling the Map between Hashtable,
> HashMap or WeakHashMap implementations makes no difference whatsoever.
>
> Black magic, or am I being dense?

<http://pscode.org/sscce.html>

--
Lew

Eric Sosman

unread,
Jul 23, 2008, 1:52:16 PM7/23/08
to
laurens...@telenet.be wrote:
> Got a weird CME when doing Map.puts or Map.gets on a private HashMap
> which gets accessed by a SINGLE thread. I also never extract iterators
> from the Map.. I only do put() and get().. yet sometimes I get
> ConcurrentModificationException. Toggling the Map between Hashtable,
> HashMap or WeakHashMap implementations makes no difference whatsoever.
>
> Black magic, or am I being dense?

Meaning no insult, I suspect the latter.

You say you "never extract iterators," but I bet you do without
realizing it. Note that the `for (Thing t : things)' loop is really
just shorthand for

for (Iterator<Thing> it = things.iterator(); it.hasNext(); ) {
Thing t = it.next();
...
}

so you may be using Iterators even if the string "Iterator" never
shows up in your source code.

From your description, I suspect `things' is either the keySet()
or entrySet() of the Map. If the "..." code executes put() on the
Map (or modifies the Map in any other way), the Iterator will throw[*]
ConcurrentModificationException at the next hasNext() call.

[*] "Will very probably throw," really. See the Javadoc.

--
Eric....@sun.com

Message has been deleted

Mike Schilling

unread,
Jul 23, 2008, 6:46:26 PM7/23/08
to

In a single thread, the behavior should be deterministic.


Eric Sosman

unread,
Jul 23, 2008, 10:05:58 PM7/23/08
to
Mike Schilling wrote:
> Eric Sosman wrote:
>> [...]

>> From your description, I suspect `things' is either the keySet()
>> or entrySet() of the Map. If the "..." code executes put() on the
>> Map (or modifies the Map in any other way), the Iterator will
>> throw[*]
>> ConcurrentModificationException at the next hasNext() call.
>>
>> [*] "Will very probably throw," really. See the Javadoc.
>
> In a single thread, the behavior should be deterministic.

If you're sure, file an RFE. ;-)

To support it, exhibit concrete implementations that "work"
in all single-threaded situations, *including* those where forty-
two independent Iterators at forty-two independent positions are
simultaneously traversing the same HashMap.keySet() at the moment
when a new key/value pair is inserted and causes a re-hash ...
Repeat the exercise for all other collection classes ...

A useful way to think about this is to imagine the Iterator
(or Enumeration) as using a "snapshot" of the collection to guide
its traversal. Change the collection, and it no longer matches
the snapshot, and the Iterator gets hopelessly lost.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Mike Schilling

unread,
Jul 24, 2008, 3:12:32 AM7/24/08
to
Eric Sosman wrote:
> Mike Schilling wrote:
>> Eric Sosman wrote:
>>> [...]
>>> From your description, I suspect `things' is either the
>>> keySet()
>>> or entrySet() of the Map. If the "..." code executes put() on the
>>> Map (or modifies the Map in any other way), the Iterator will
>>> throw[*]
>>> ConcurrentModificationException at the next hasNext() call.
>>>
>>> [*] "Will very probably throw," really. See the Javadoc.
>>
>> In a single thread, the behavior should be deterministic.
>
> If you're sure, file an RFE. ;-)
>
> To support it, exhibit concrete implementations that "work"
> in all single-threaded situations, *including* those where forty-
> two independent Iterators at forty-two independent positions are
> simultaneously traversing the same HashMap.keySet() at the moment
> when a new key/value pair is inserted and causes a re-hash ...
> Repeat the exercise for all other collection classes ...

It's very simple: all 42 will throw CMEs when next accessed. The
implementation is quite simple. The underlying map has a "number of
modifications" counter that it increments whenever it's modified, e.g.
when a new key is added. Each iterator makes a copy of that number
when it's created. Whenever the iterator is accessed and its
modification count doesn't match the map's, it throws a CME. In a
single-threaded environment, this works perfectly. The weasel-wording
in the Javadoc about "will probably throw" is to cover multi-threaded
cases; since the accesses to the two modification counts are not
synchronized, it's possible that a change to them made in one thread
won't yet be visible in another.


Eric Sosman

unread,
Jul 24, 2008, 8:25:43 AM7/24/08
to
Mike Schilling wrote:
> Eric Sosman wrote:
>> Mike Schilling wrote:
>>> Eric Sosman wrote:
>>>> [...]
>>>> From your description, I suspect `things' is either the
>>>> keySet()
>>>> or entrySet() of the Map. If the "..." code executes put() on the
>>>> Map (or modifies the Map in any other way), the Iterator will
>>>> throw[*]
>>>> ConcurrentModificationException at the next hasNext() call.
>>>>
>>>> [*] "Will very probably throw," really. See the Javadoc.
>>> In a single thread, the behavior should be deterministic.
>> If you're sure, file an RFE. ;-)
>>
>> To support it, exhibit concrete implementations that "work"
>> in all single-threaded situations, *including* those where forty-
>> two independent Iterators at forty-two independent positions are
>> simultaneously traversing the same HashMap.keySet() at the moment
>> when a new key/value pair is inserted and causes a re-hash ...
>> Repeat the exercise for all other collection classes ...
>
> It's very simple: all 42 will throw CMEs when next accessed.

Ah! Sorry; I had misunderstood what you meant by
"deterministic," and thought you imagined all the Iterators
could somehow take the Map modifications in stride and keep
on iterating. My apologies for mis-reading.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Mike Schilling

unread,
Jul 24, 2008, 12:30:58 PM7/24/08
to

No worries.


Daniel Pitts

unread,
Jul 25, 2008, 3:31:32 PM7/25/08
to
laurens...@telenet.be wrote:
> Got a weird CME when doing Map.puts or Map.gets on a private HashMap
> which gets accessed by a SINGLE thread. I also never extract iterators
> from the Map.. I only do put() and get().. yet sometimes I get
> ConcurrentModificationException. Toggling the Map between Hashtable,
> HashMap or WeakHashMap implementations makes no difference whatsoever.
>
> Black magic, or am I being dense?
>
Its hard to tell without looking at the code and stackdump. What line is
the exception on?

BTW, using the for-each syntax is equivalent to using iterators.

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

0 new messages