10

I have been reading for concurency since yesterday and i dont know much things... However some things are starting to getting clear...
I understand why double check locking isnt safe (i wonder what is the propability the rare condition to occur) but volatile fixes the issue in 1.5 +....
But i wonder if this occurs with putifAbsent

like...

myObj = new myObject("CodeMonkey");
cHashM.putIfAbsent("keyy",myObj);  

Then does this ensures that myObj would be 100% intialiased when another thread does a cHashM.get() ??? Because it could have a reference isnt completely initialised (the double check lock problem)

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
GorillaApe
  • 3,611
  • 10
  • 63
  • 106

4 Answers4

5

If you invoke concurrentHashMap.get(key) and it returns an object, that object is guaranteed to be fully initialized. Each put (or putIfAbsent) will obtain a bucket specific lock and will append the element to the bucket's entries.

Now you may go through the code and notice that the get method doesnt obtain this same lock. So you can argue that there can be an out of date read, that isn't true either. The reason here is that value within the entry itself is volatile. So you will be sure to get the most up to date read.

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
John Vint
  • 39,695
  • 7
  • 78
  • 108
  • So if i understand correctly there is no problem ,like in the classic double check locking paradigm ? – GorillaApe May 13 '11 at 20:36
  • @Parhs: Right, there is no problem. – ColinD May 13 '11 at 20:45
  • You are correct. You actually answered it yourself in your question with 'but volatile fixes the issue in 1.5 +' Since the value returned from the CCHM is a volatile value, it too is safe from partial initialization. – John Vint May 13 '11 at 20:45
  • @JohnVint I have a similar question [here](http://stackoverflow.com/questions/40831817/how-to-make-concurrent-hash-map-thread-safe-with-get-and-put-as-an-atomic-operat) on performing get and put operation atomically on CHM. Can you help me out over there? – john Nov 27 '16 at 19:05
  • @david I answered your question there. The only time you'll need the check-then-set logic is if it needs to be memoized. – John Vint Nov 28 '16 at 13:27
5

putIfAbsent method in ConcurrentHashMap is check-if-absent-then-set method. It's an atomic operation. But to answer the following part: "Then does this ensures that myObj would be 100% intialiased when another thread does a cHashM.get() ", it would depend on when the object is put into the HashMap. Usually there is a happens-before precedence, i.e., if the caller gets first before the object is placed in the map, then null would be returned, else the value would be returned.

kuriouscoder
  • 5,394
  • 7
  • 26
  • 40
  • null to be returned wouldnt be a prb but a reference to a non fully constructed-initiliased object would be. (the problem with double check locking) – GorillaApe May 13 '11 at 20:38
  • +1 Upvoted for "Atomic" Atomic takes care of ordering of threads, So .put() method is not called twice ConcurrentHashMap takes care of synchronisation of Writer .put() method threads – Karan Kaw Oct 10 '19 at 10:05
2

The relevant part of the documentation is this:

Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a ConcurrentMap as a key or value happen-before actions subsequent to the access or removal of that object from the ConcurrentMap in another thread.

-- java.util.ConcurrentMap

So, yes you have your happens-before relationship.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
1

I'm not an expert on this, but looking at the implementation of Segment in ConcurrentHashMap I see that the volatile field count appears to be used to ensure proper visibility between threads. All read operations have to read the count field and all write operations have to write to it. From comments in the class:

Read operations can thus proceed without locking, but rely
on selected uses of volatiles to ensure that completed
write operations performed by other threads are
noticed. For most purposes, the "count" field, tracking the
number of elements, serves as that volatile variable
ensuring visibility.  This is convenient because this field
needs to be read in many read operations anyway:

   - All (unsynchronized) read operations must first read the
     "count" field, and should not look at table entries if
     it is 0.

   - All (synchronized) write operations should write to
     the "count" field after structurally changing any bin.
     The operations must not take any action that could even
     momentarily cause a concurrent read operation to see
     inconsistent data. This is made easier by the nature of
     the read operations in Map. For example, no operation
     can reveal that the table has grown but the threshold
     has not yet been updated, so there are no atomicity
     requirements for this with respect to reads.
ColinD
  • 108,630
  • 30
  • 201
  • 202