开发者

During a data race can a thread ever read initial null value of volatile variable? especially when a non null value is assigned to it in constructor?

开发者 https://www.devze.com 2023-01-28 12:05 出处:网络
What puzzles me is this. Java doc of HashEntry in ConcurrentHashMap (jdk1.6.0_16) ...Because the value field is volatile, not final, it is legal wrt the Java Memory Model for an unsynchronized rea
  • What puzzles me is this.

Java doc of HashEntry in ConcurrentHashMap (jdk1.6.0_16)

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

  • here is the implementation of get method of ConcurrentHashMap#Segment

    
    V get(Object key, int hash) {
            if (count != 0) { // read-volatile
                HashEntry e = getFirst(hash);
                while (e != null) {
                    if (e.hash == hash && key.equals(e.key)) {
                        V v = e.value;
                        if (v != null)
                            return v;
                        return readValueUnderLock(e); // recheck
                    }
                    e = e.next;
                }
            }
            return null;
        }
    
  • And of readValueUnderLock


V readValueUnderLock(HashEntry e) {
        lock();
        try {
            return e.value;
        } finally {
            unlock();
        }
    }
  • Based of my reading and understanding every thread will read an up to date value of volatile variable.

  • So when will a thread re开发者_开发知识库ad initial null value? especially in HashEntry where value is assigned before the constructor completes. (Also note that HashEntry's reference never escapes its constructor.)

  • I am stumped, can some one explain the above java doc of HashEntry in ConcurrentHashMap (jdk1.6.0_16). and why that extra precaution locking is required?


When Java 1.5 was released, there was a provision in the JMM that said that the HashEntry can be partially initialized. That is, when a thread is putting into the map, the HashEntry is created and assigned as a reference to either the bucket head or a collison member. At that time the value of the entry, may have not been assigned to be seen by the other threads.

The CHM assumes that if the entry isnt null, then the value shouldn't be null so readValueUnderLock was put in as a failsafe.

I asked DL about this exact situation and he said that despite the possibility of it happening, it never should. He also said that since 1.6, that issue won't happen.


You must make sure that the reference to the Map cannot be used by anyone, before the constructor completes. That should be easy to do when it is a private field and only accesses by getter methods - including in the class where that field is held.

The constructor will finish before the instance getter method will be able to be called.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号