2

I am going through source code of ConcurrentHashMap in jdk 7 and have few questions. I have already gone through all the questions on CHM on StackOverFlow, but could not find the answer.

  1. Is get() operation in CHM guaranteed to get correct value of put() by other thread? I am asking this as get is not synchronized unless it sees the null value. How null value ensures that same record is being updated by other thread and then get is used with lock?

  2. This is related to HashEntry static class where key and values are stored.

    a. Why is this class final? Is it just to make sure nobody subclasses it? What happens if somebody subclasses it -- is something wrong with that?

    b. How does making the next field final helps in getting thread safety?

    c. Why is Key also final? (I am not sure why Key is final in HashMap also)

Gray
  • 115,027
  • 24
  • 293
  • 354
AKS
  • 1,393
  • 3
  • 19
  • 29

1 Answers1

6

Is get operation in CHM guaranteed to get correct value of put by other thread?

It certainly is guaranteed as long as the put() has completed before the call to get(). CHM uses volatile accesses and other locks internally to ensure the data is synchronized, not necessarily the synchronized keyword.

I am asking this as get is not synchronized unless it sees the null value. How null value ensures that same record is being updated by other thread and then get is used with lock?

I assume you are referring to this javadoc:

Because the value field is volatile, not final, it is legal wrt the Java Memory Model for an unsynchronized reader to see null instead of initial value when read via a data race. Although a reordering leading to this is not likely to ever actually occur, the Segment.readValueUnderLock method is used as a backup in case a null (pre-initialized) value is ever seen in an unsynchronized access method.

This is trying to explain that the value is not final so therefore the initialization in the constructor could be reordered and a reader could see a null value. I assume this is why CHM is not allowed to store null values. That allows them to test for null and then do another get inside a synchronized block.

For more information around constructor reordered, see: Is reordering of instance initialization and assignment to a shared variable possible?

Why is the HashEntry class final? Is it just to make sure nobody subclasses it ?

Yes. This ensures that the class cannot be subclassed. This ensures immutability. If someone subclassed it, they could change the visibility of the fields and break the concurrency contract.

How does making next [[field]] final helps in getting thread safety?

The next field (as well as the key and hash fields) is final because this ensures that the field is fully initialized in the constructor. This does improve thread safety since the initialization cannot then be reordered past the end of the constructor by the optimizer and all threads are guaranteed to see the data.

See above for information about the value field and how they protect against it not being final which allows put(...) to overwrite.

Why is Key also final? (I am not sure why Key is final in HashMap also)

Same answer as the HashEntry.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Re: "It won't compile [if someone subclasses `HashEntry`]": That seems like a non-answer. The OP is asking "why is this `final`, what would be wrong with someone subclassing it?" and your answer is "the problem with someone subclassing it is that it wouldn't compile because it's `final`". – ruakh Aug 30 '13 at 20:22
  • @ruakh - The real answer to that question is in the next response: *Because I assume that this ensures immutability. If someone subclassed it they could change the visibility of the fields and break the concurrent contract.* – DaoWen Aug 30 '13 at 20:23
  • Re: "[making next final] ensures immutability. If someone subclassed it [...]": The class is `final`, so there's no risk of subclassing; so you can't invoke the risk of subclassing to explain why one of the fields is `final`. – ruakh Aug 30 '13 at 20:24
  • @DaoWen: No, the next response is referring to a different occurrence of `final`. (And anyway, there's no reason to include a vapid non-answer, even if it's immediately followed by a real answer.) – ruakh Aug 30 '13 at 20:26
  • I've expanding that answer @ruakh to point out that the reason _why_ it can't be subclassed is due to visibility. – Gray Aug 30 '13 at 20:26
  • @ruakh you just COMPLETELY screwed my answer. -- – Gray Aug 30 '13 at 20:32
  • @Gray: Sorry, I was trying to remove the obnoxious parts. Feel free to revert, and I'll just downvote instead. :-/ – ruakh Aug 30 '13 at 20:33
  • Jesus that really screwed me dude. @ruakh Please don't do that in the future or at least give someone a couple of minutes to respond to some good feedback in comments. – Gray Aug 30 '13 at 20:37
  • @Gray: Sorry. I guess "I've expanding" meant "I'm expanding", but I took it to mean "I've expanded"; that is, I thought you were saying you were done. I didn't mean to interfere with ongoing edits. Your current answer is good; +1. – ruakh Aug 30 '13 at 20:38
  • I had expanded it (past tense) @ruakh. Then you overwrote my expansion. Take a look at the end history. – Gray Aug 30 '13 at 20:42
  • Well, the edit-history conflates edits by a single editor within a five-minute span, so it doesn't clarify. Suffice it to say, I clicked "edit" *after* seeing your comment, so if it overwrote part of your expansion, then that means that part of your expansion went through *after* you posted your comment. (Which is fine -- I often make a series of edits, too, and I'm not judging you -- but given how easy it is to rollback an edit, and to recover content from an old edit, I think you might be overreacting a little.) – ruakh Aug 30 '13 at 20:50
  • I did not see a rollback button on your edit @ruakh only mine. The rollback button rolls back _to_ that change or rolls it back. Never had to use it before. – Gray Aug 30 '13 at 20:54
  • @Gray: I see. Yeah, I found that button confusing, too, the first time I needed it. – ruakh Aug 30 '13 at 21:00