Use HashMap for better multithreaded performance

420 views
Skip to first unread message

SuperNunrg

unread,
Jul 29, 2020, 2:57:37 AM7/29/20
to mechanical-sympathy
Hi experts,

I found this article https://www.ibm.com/developerworks/library/j-hashmap/index.html and stuck upon that statement 

static volatile Map currentMap = null;   // this must be volatile
static Object lockbox = new Object();  
public static void buildNewMap() {       // this is called by the producer    
   
Map newMap = new HashMap();          // when the data needs to be updated
   
synchronized (lockbox) {                 // this must be synchronized because of the Java memory model
     
// .. do stuff to put things in newMap
      newMap
.put(....);
      newMap
.put(....);
   
}                
/* After the above synchronization block, everything that is in the HashMap is visible outside this thread */
 
/* Now make the updated set of values available to the consumer threads.  As long as this write operation can complete without being interrupted,
   and is guaranteed to be written to shared memory, and the consumer can live with the out of date information temporarily, this should work fine */

 
    currentMap
= newMap;
 
}
public static Object getFromCurrentMap(Object key) {
   
Map m = null;
   
Object result = null;
 
    m
= currentMap;               // no locking around this is required
   
if (m != null) {              // should only be null during initialization
     
Object result = m.get(key); // get on a HashMap is not synchronized
     
     
// Do any additional processing needed using the result
   
}
   
return(result);
}


The synchronized block and the volatile keyword in Listing 1 are required because no happens-before relationship exists between the writes to the currentMap and the reads from currentMap

I don't understand why we need a synchronized block in this case. isn't it enough, in this case, to publish a newly created and populated hashmap through a volatile variable to make other thread see its contents? 

Thanks in advance

Peter Veentjer

unread,
Jul 29, 2020, 3:05:26 AM7/29/20
to mechanica...@googlegroups.com
The volatile variable ensures that there is a happens-before edge between the write and the read.

So the synchronized block isn't needed; it even doesn't provide any visibility guarantee because:
- currentMap = newMap is not send in the synchronized block
- currentMap isn't read in the synchronized block.

I'm not completely sure what the purpose is of the synchronized block.

Keep in mind that this article is of 2007. So it is pretty old.

--
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/337d1e27-b31f-4e57-a937-62929fad54a2o%40googlegroups.com.

Henri Tremblay

unread,
Jul 29, 2020, 7:31:55 AM7/29/20
to mechanica...@googlegroups.com
Agreeing with Peter. The map is local so it is safe until copied to currentMap. 

I think the idea here was to make sure the content of the map was correctly published through synchronization.
As you correctly mentioned, the volatile causes a happens-before that makes sure of that.

SuperNunrg

unread,
Aug 27, 2020, 7:18:28 AM8/27/20
to mechanical-sympathy

Thank you all for answers. Let me ask one more question here.
Guava has a lot of useful classes such as
there are two classes MemoizingSupplier and NonSerializableMemoizingSupplier 
the first one has delegate marked as final and second as volotile. Why is that? could NonSerializableMemoizingSupplier has its delegate marked as final?
has it something to do with GC?

Henri Tremblay

unread,
Aug 27, 2020, 8:58:42 AM8/27/20
to mechanica...@googlegroups.com
MemoizingSupplier is keeping the delegate forever.
NonSerializableMemoizingSupplier is releasing the delegate (delegate = null) when the value is captured because it's not needed anymore.

That's why one is final and the other volatile.

Why they are not behaving the same way is a good question.

--
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.

SuperNunrg

unread,
Aug 27, 2020, 10:08:04 AM8/27/20
to mechanica...@googlegroups.com
MemoizingSupplier is keeping the delegate forever.
NonSerializableMemoizingSupplier is releasing the delegate (delegate = null) when the value is captured because it's not needed anymore.

yes, that's pretty clear from the code. 

That's why one is final and the other volatile.

and this one is not.

For me it seems that final serves the purpose of safe initialization in case that another thread which is actually "initializing"(calls get() method on an instance of a MemozingSupplier) could properly see a delegate.
And in case of NonSerializableMemoizingSupplier volatile seems to do the same thing. Does final adds any special properties over volatile than an object is serialized?



Henri Tremblay

unread,
Aug 27, 2020, 2:26:58 PM8/27/20
to mechanica...@googlegroups.com
No. But final is better than volatile. Hotspot will consider it more constant. And reading it doesn't require a barrier (some in this list might add a little precision on that because final is not fully final but I will ignore that for now) since we know it's the right value from the start.

The bottom line is: Always put final when you can on a class attribute (we don't care about parameters and variables being final. I just consider it to be visual noise)

Reply all
Reply to author
Forward
0 new messages