Java-容器-并发-ConcurrentHashMap

版权声明:欢迎转载,请注明作者和出处 https://blog.csdn.net/baichoufei90/article/details/83897346

Java-容器-并发-ConcurrentHashMap

0x01 摘要

本文讲讲Java中使用率极高的线程安全类ConcurrentHashMap

未完成

0x02 为什么线程安全

0x03 源码解析

3.1 初始化

3.2 放入

3.3 取出

3.3.1 源码

public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
        int h = spread(key.hashCode());
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) {
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }
            else if (eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }

3.3.2 spread方法

static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash

static final int spread(int h) {
		// h 异或 (h 无符号右移 16位) 逻辑与 0x7fffffff
        return (h ^ (h >>> 16)) & HASH_BITS;
}

方法里的参数hhashCode

  • 原始h
    0011101101100011 1111111100101110
  • h >>> 16
    0000000000000000 1011101101100011
  • h ^ (h >>> 16)
    0011101101100011 0100010001001101
  • h ^ (h >>> 16) & HASH_BITS;
    0011101101100011 0100010001001101

需要注意的是,这里HASH_BITS = 0x7fffffff,也就是
011111111111111 11111111111111111

注意到首位为0,作用就是将前面计算的结果最高位(符号位)强制设为0,避免出现负数。因为负数在ConcurrentHashMap中有特殊设计:

static final int MOVED     = -1; // hash for forwarding nodes
static final int TREEBIN   = -2; // hash for roots of trees
static final int RESERVED  = -3; // hash for transient reservations

现在看来,spread这么做的目的无非就是将高16位和低16位融合增加随机性,同时又保留了原有高位,最大限度的避免碰撞。而且这一切都是位运算,效率极高。

jdk说明
散列(XORs) higher bits of hash to lower and also forces top bit to 0.
Spreads (XORs)将hash值的高16位右移到低16位,然后将最高位(符号位)置为0.

Because the table uses power-of-two masking, sets of hashes that vary only in bits above the current mask will always collide.(Among known examples are sets of Float keys holding consecutive whole numbers in small tables.)
因为此表用二次掩码,所以仅在当前掩码之上的位上变化的散列集将总是发生冲突(其中已知的例子是Float键集在小表格中保持连续的整数)

So we apply a transform that spreads the impact of higher bits downward.
所以我们采用一个变换,它可以向下扩展高位的作用力

There is a tradeoff between speed, utility, and quality of bit-spreading.
我们需要在速度,可用性和位散列的质量之间来权衡

Because many common sets of hashes are already reasonably distributed (so don’t benefit from spreading), and because we use trees to handle large sets of collisions in bins,
由于许多常见的数据集合的hash值已经合理分布(所以不会从散列中获益),还因为我们用树来处理bin中大量的集合冲突,

we just XOR some shifted bits in the cheapest possible way to reduce systematic lossage, as well as to incorporate impact of the highest bits that would otherwise never be used in index calculations because of table bounds.
所以我们仅需要对一些移位进行异或运算,这是尽可能的低开销方式来减少系统性能损失, 以及合并由于表边界而不可用于索引计算的最高位的影响。

3.4 扩容

猜你喜欢

转载自blog.csdn.net/baichoufei90/article/details/83897346