Java Memory Model, ConcurrencyHashMap and guarantee of iterator

129 views
Skip to first unread message

r r

unread,
Sep 12, 2022, 8:30:59 AM9/12/22
to mechanical-sympathy
Hello,
let's look for the following piece of code:

c = new ConcurrentHashMap<Integer, Boolean>();
T1:  
    c.put(1, true);
    for (Boolean b : c.values()) {
        print(b);
    }
T2:  
    c.put(2, true);
    for (Boolean b : c.values()) {
        print(b);
    }

Is it guaranteed by JMM that any thread (T1 or T2) prints true, true?
To put it in another way, is it guaranteed that T1 or T2 observes both c.put?

If yes / no, why?
Thanks in advance for your time.

Peter Veentjer

unread,
Sep 12, 2022, 8:42:53 AM9/12/22
to mechanica...@googlegroups.com
If T1 would run first, the content of the ConcurrentHashMap is (1,true), and therefore there is only 1 value.

So it will print 'true' and not 'true,true' because T2 has not run yet.

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/mechanical-sympathy/0945e8e3-1070-4166-b269-1c4e6c49da3en%40googlegroups.com.

Alper Tekinalp

unread,
Sep 12, 2022, 9:01:45 AM9/12/22
to mechanica...@googlegroups.com
From util.concurrent:

> Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.

So ether one of threads will print (true, true) I guess.

Peter Veentjer

unread,
Sep 12, 2022, 9:11:13 AM9/12/22
to mechanica...@googlegroups.com
I think this example is better:

class Foo{
  int x;
}

Thread1:
   Foo foo = new Foo();
   foo.x = 10;                                           (1)
   concurrentMap.put("1", foo);             (2)

Thread2:
    Foo foo = concurrentMap.get("1");   (3)
    if(foo!=null) print(foo.x);                   (4)

There is a happens-before edge between (1) and (2) due to program-order rule. And also between (3) and (4) there is a happens-before edge due to program-order rule.

And if thread2 sees the non null value, then there is a happens-before edge between (2) and (3) due to either the volatile variable rule or monitor lock rule (often this is called memory consistency effects on e.g. queues)

Since the happens-before relation is transitive, there is a happens-before edge between (1) and (4).

r r

unread,
Sep 12, 2022, 10:50:56 AM9/12/22
to mechanica...@googlegroups.com
Thanks, for your response. I know that output "true" is possible. My question is: Is it guaranteed by JMM that one of T1, T2 will print "true, true"? 

Avi Zohary

unread,
Sep 12, 2022, 11:44:31 AM9/12/22
to mechanical-sympathy
I think the issue here is more the ConcurrentHashMap that doesn't promise you'll get both entries when calling c.values() in either one of the threads.

r r

unread,
Sep 12, 2022, 2:46:38 PM9/12/22
to mechanical-sympathy
> I think the issue here is more the ConcurrentHashMap that doesn't promise you'll get both entries when calling c.values() in either one of the threads.

What do you mean?

Vijayant Dhankhar

unread,
Sep 12, 2022, 3:26:01 PM9/12/22
to mechanical-sympathy
For your original formulation for the problem.. 

> Is it guaranteed by JMM that any thread (T1 or T2) prints true, true?
> To put it in another way, is it guaranteed that T1 or T2 observes both c.put?

Yes, one of the thread will print true, true as there is a happens-before between the two writes to concurrent hash map (even if they are possibly on the keys that map to different bins)

r r

unread,
Sep 12, 2022, 3:36:09 PM9/12/22
to mechanical-sympathy
@Vijayant Dhankhar, thanks. 

How do you know it, I mean:
* that there is a happens-before between writes ()
* c.values is ensured to see two writes?

Avi Zohary

unread,
Sep 12, 2022, 6:03:12 PM9/12/22
to mechanical-sympathy
I'm not absolutely sure about this, but it is possible that each thread will be running on different cores, and their respective put operations will fall into different bins in the CHM. Looking at the CHM, there is no guarantee that reads will return data from different threads' concurrent writes. 
However, the returned Collection from the call to values() returns a collection that is backed by the CHM data. So there is a second race condition in the reads - it's possible that each thread will see only the data that it wrote on its own, and it's possible that any one of them will see both writes. 
Reply all
Reply to author
Forward
0 new messages