[concurrency-interest] ConcurrentHashMapV8

David M. Lloyd david.lloyd at redhat.com
Wed Oct 5 19:46:57 EDT 2011


On 10/5/11 4:12 PM, Joe Bowbeer wrote:
> On Wed, Oct 5, 2011 at 3:31 PM, David M. Lloyd wrote:
>
>     On 10/5/11 6:11 AM, Doug Lea wrote:
>
>         I'm still contemplating changes in handling null-returns
>         in the new compute methods. But in the mean time, here
>         is another tiny corner-case issue that is handled differently
>         in ConcurrentHashMapV8 than in the existing j.u.c version.
>         I consider it just a misfeature-fix, but Joe Bowbeer remains
>         nervous about it, so urged me to post and solicit reaction.
>
>         This takes a fair amount of context to set up:
>         [...snip...]
>
>         For example,
>         you would be surprised and unhappy if you did
>         Object[] a = myArrayList.toArray();
>         a[0] = 17;
>         and then found out that this caused myArrayList.get(0)
>         to also now return 17.
>
>         In the case of ConcurrentHashMap, this means that the
>         kind of Entry you get for the elements of entrySet.toArray
>         should NOT write back to the map you got them from.
>         In other words:
>         Object[] a = myMap.entrySet().toArray();
>         (Entry[])a[0].setValue(17);
>         should not change myMap.get(keyFor0) to return 17.
>
>
>     I disagree with this conclusion; these scenarios aren't really the
>     same.  The general contract of toArray() is to return an array
>     consisting of all the values in the collection - I think
>     interpreting it such that it can return copies of the values is a
>     stretch.  I can't think of any case where we'd actually copy the
>     values in normal collections; I don't see why an entry set should be
>     any different, magical write-through notwithstanding.
>
>     For example if I did:
>
>     Object[] a = myMap.entrySet().toArray();
>
>     I would expect the same result as if I did:
>
>     Object[] a = new
>     ArrayList<Entry<Blah,Blah>>(__myMap.entrySet()).toArray();
>
>     I don't think toArray should be special here.  I think this is the
>     "most correct" interpretation of this requirement, and in any case
>     is the one I've adhered to whenever developing collection
>     implementations.  I think that there should be no difference between
>     the values in a toArray() result and the values you'd get back from
>     a set iterator.
>     --
>     - DML
>
>
> I agree with your interpretation and expectation regarding toArray.  But
> the Map.Entry documentation (below) limits their validity to the
> duration of the iteration.  How do you reconcile the two?
>
> http://download.oracle.com/javase/6/docs/api/java/util/Map.Entry.html
>
> "The *only* way to obtain a reference to a map entry is from the
> iterator of this [entry-set] collection-view. These Map.Entry objects
> are valid *only* for the duration of the iteration; more formally, the
> behavior of a map entry is undefined if the backing map has been
> modified after the entry was returned by the iterator, except through
> the setValue operation on the map entry."

Well be cautious how you define "the duration".  I think that the real 
definition as given by the "more formally" section relates to modifying 
the map after an iterator is created.  And I really interpret this as 
meaning that the entry *must* be valid before such a modification, and 
*may* be valid afterward.  For an implementer this means you are allowed 
to keep them valid for as long as is reasonable or convenient.  From a 
user perspective it means that you'd better not rely on it unless you 
know what implementation you're dealing with and what guarantees it 
makes, above and beyond what is specified.

But for ConcurrentMap in particular, this restriction needs a rethink 
given that the whole _point_ of the thing is to provide concurrent 
access; entry iterators become a lot less useful if you must freeze 
write access to the whole map while you iterate.  I think it might be a 
good idea to override entrySet() for the purpose of adding documentation 
to clarify this.

In any case, I think you can say that "during iteration" is equal to the 
time in which you have any active references to the items returned by 
the iterator, because no other definition makes sense.  So if toArray() 
is defined in terms of iteration then there is no conflict - using the 
array is the same as using the values returned by the iterator as they 
are returned; the iteration is seen to be in progress until the last 
entry is "discarded".  I don't see anything in the docs that contradict 
this.


-- 
- DML


More information about the Concurrency-interest mailing list