ConcurrentHashMap源码阅读补充1——为什么使用Treebin而不是现成TreeMap等?

1.官方文档的说明

参考先前ConcurrentHashMap类实现说明翻译:

TreeBins use a special form of comparison for search and
related operations (which is the main reason we cannot use
existing collections such as TreeMaps). TreeBins contain
Comparable elements, but may contain others, as well as
elements that are Comparable but not necessarily Comparable for
the same T, so we cannot invoke compareTo among them. To handle
this, the tree is ordered primarily by hash value, then by
Comparable.compareTo order if applicable.  On lookup at a node,
if elements are not comparable or compare as 0 then both left
and right children may need to be searched in the case of tied
hash values. (This corresponds to the full list search that
would be necessary if all elements were non-Comparable and had
tied hashes.) On insertion, to keep a total ordering (or as
close as is required here) across rebalancings, we compare
classes and identityHashCodes as tie-breakers. The red-black
balancing code is updated from pre-jdk-collections
(http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
based in turn on Cormen, Leiserson, and Rivest "Introduction to
Algorithms" (CLR).

Treebins在搜索和相关操作中使用了特殊形式的比较(这也是不能使用现存集合例如TreeMap的主要原因)。Treebins包含Comparable元素,但是也可能包含其他类型的(不能调用compareTo的元素)。

2.看看TreeMap对元素的要求

The map is sorted according to the Comparable natural
ordering of its keys, or by a  Comparator provided at map
creation time, depending on which constructor is used.
  • 要么元素是Comparable类型的
  • 要么提供一个比价器Comparator

其部分put代码如下:

    public V put(K key, V value) {
        Comparator cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
             ...
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable k = (Comparable) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);

可见在插入元素时,要么调用比较器comparator的compara,要么调用compareTo方法确定元素要插入红黑树的位置。

所以这里有一个核心区别:对于TreeMap,是一个SortedMap,本质上是针对有序、可排序元素使用的。而ConcurrentHashMap是一个HashMap,本质上并不要求元素有序,而是为了存储键值对而已,只不过为了更快的存取。因此,必然不要求其有序。另外存储的元素是Comparable时,但可能不是同一种类型的。例如Integer和Double。

public class CHMTest {

    public static void main(String[] args) {
//        Map  map =  new ConcurrentHashMap<>();
        Map  map =  new TreeMap<>();
        map.put(12, "12");
        map.put(13.0, "13");
        System.out.println(map);
    }
}

使用TreeMap时结果会抛出异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
    at java.lang.Double.compareTo(Double.java:49)
    at java.util.TreeMap.put(TreeMap.java:568)
    at com.enjoy.learn.core.concurrency.CHMTest.main(CHMTest.java:21)

因为调用Double.compareTo时,会对入参Integer进行转型,但是Double和Integer不属于父子类关系。


但是显然ConcurrentHashMap是可以的:

    public static void main(String[] args) {
        Map  map =  new ConcurrentHashMap<>();
//        Map  map =  new TreeMap<>();
        map.put(12, "12");
        map.put(13.0, "13");
        System.out.println(map);
    }

结果:

{13.0=13, 12=12}

所以其红黑树为了兼容这种表现,必须进行改进,使得能够放入任意键值对。

你可能感兴趣的:(ConcurrentHashMap源码阅读补充1——为什么使用Treebin而不是现成TreeMap等?)