Question

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)

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top