8

In JDK 1.6, Doug Lea uses final preceding the next field.

static final class HashEntry<K,V> {
    final K key;
    final int hash;
    volatile V value;
    final HashEntry<K,V> next;

Whereas in JDK 1.7, the next field is preceded by volatile. I also notice that in JDK 1.7, the get method adopts getObjectVolatile method to read the value field, which has the volatile load semantics.

I have no sense why Doug Lea previously uses final. If there are problems with correctness, then how could he replace it with volatile in JDK 1.7(also JDK 1.8)?

Edit:

Specifically, my question is that could we replace final with volatile in JDK 1.6's implementation?

chain ro
  • 737
  • 2
  • 10
  • 21
  • 1
    This class is not in CHM in Java 8. – assylias Jul 15 '15 at 12:25
  • 1
    OK, if that's your question, then no, you can't. The reason the modifier was changed is that the implementation was completely changed. This is not an isolated change. – RealSkeptic Jul 15 '15 at 12:41
  • 1
    @RealSkeptic, could you present some details, or articles for the explanation? Thanks. – chain ro Jul 15 '15 at 12:43
  • @assylias, sorry, the whole implementation is changed in Java 8, which uses `Node` to represent the Key-value entry. I should point it out. – chain ro Jul 15 '15 at 12:45

2 Answers2

2

For your first question:

I have no sense why Doug Lea previously uses final. If there are problems with correctness, then how could he replace it with volatile in JDK 1.7(also JDK 1.8)?

It wasn't a matter of correctness. Both implementations are correct in terms of thread-safety. What was trying to be solved was reducing the initial footprint of the CHM. In Java 6, making the next field final required the object be created with at least a place holder. This caused excessive empty object creation and so was changed to offer create-when-needed semantics.

Specifically, my question is that could we replace final with volatile in JDK 1.6's implementation?

Certainly as long as the operations continue to be sequentially consistent, which they are.


One of Doug Lea's comments touches on this design change

 /* 
 * ...
 * Historical note: The previous version of this class relied
 * heavily on "final" fields, which avoided some volatile reads at
 * the expense of a large initial footprint.  Some remnants of
 * that design (including forced construction of segment 0) exist
 * to ensure serialization compatibility. 
 */

So to answer another question you are probably having, why was final chosen initially? To prevent some volatile reads later on.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • I have the same idea, but cannot confirm it by myself. I wonder if you come up with similar questions about Java APIs, how do you handle them? Thanks. – chain ro Jul 15 '15 at 15:56
0

It is not a matter of replacing final with volatile. Like RealSkeptic it was changed among many other methods. The purpose might be the optimization of ConcurrentHashMap.remove(). In JDK1.6 the list that stores bucket (objects grouped by hashcode) is CopyOnWrite so inside remove() part of list is copied, in JDK1.7 only next pointer is changed.

Community
  • 1
  • 1
user158037
  • 2,659
  • 1
  • 24
  • 27