JDK 8 ConcrrentHashMap 源码解析

【本文是为了梳理知识的总结性文章,总结了一些自认为相关的重要知识点,只为巩固记忆以及技术交流,忘批评指正。其中参考了很多前辈的文章,包括图片也是引用,如有冒犯,侵删。】

0 存储结构

从底层实现来看,ConcurrentHashMap和HashMap一样都是数组+链表+红黑树(JDK1.8 为了优化链表查询性能新增红黑树)实现的。

1 类定义

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable 

 

2 静态常量

    // 最大容量,不能超过该值
    private static final int MAXIMUM_CAPACITY = 1 << 30;
    
    // 初始容量,默认是16
    private static final int DEFAULT_CAPACITY = 16;
    
    // 最大可能的数组大小
    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    // 默认支持并发更新的线程数量
    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

    // 默认负载因子
    private static final float LOAD_FACTOR = 0.75f;

    // 同一个桶中链表元素数量超过8可能会转化为树
    static final int TREEIFY_THRESHOLD = 8;

    // 删除冲突节点后,桶中节点数目小于这个数,红黑树就恢复成链表
    static final int UNTREEIFY_THRESHOLD = 6;

    // 扩容的临界值
    static final int MIN_TREEIFY_CAPACITY = 64;

    // 扩容时,并发转移节点(transfer方法)时,每次转移的最小节点数
    private static final int MIN_TRANSFER_STRIDE = 16;

    // 生成sizeCtl所使用的bit位数
    private static int RESIZE_STAMP_BITS = 16;

    // 进行扩容所允许的最大线程数
    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;

    // 记录sizeCtl中的大小所需要进行的偏移位数
    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;

    // 以下常量定义了特定节点类hash字段的值
    static final int MOVED     = -1; // ForwardingNode类对象的hash值
    static final int TREEBIN   = -2; // TreeBin类对象的hash值
    static final int RESERVED  = -3; // ReservationNode类对象的hash值
    static final int HASH_BITS = 0x7fffffff; /// 普通Node节点的hash初始值

    // CPU的数量 
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    // 进行序列化的属性
    private static final ObjectStreamField[] serialPersistentFields = {
        new ObjectStreamField("segments", Segment[].class),
        new ObjectStreamField("segmentMask", Integer.TYPE),
        new ObjectStreamField("segmentShift", Integer.TYPE)
    };

3 属性

    // 存储元素的数组,其长度必须为2的次方
    transient volatile Node<K,V>[] table;
    // 扩容时新生成的数组,其大小为原来的两倍
    private transient volatile Node<K,V>[] nextTable;
    // 基本计数
    private transient volatile long baseCount;
    //
    /**
     * Table initialization and resizing control.  When negative, the
     * table is being initialized or resized: -1 for initialization,
     * else -(1 + the number of active resizing threads).  Otherwise,
     * when table is null, holds the initial table size to use upon
     * creation, or 0 for default. After initialization, holds the
     * next element count value upon which to resize the table.
     */
    // 默认为0,用来控制对表初始化和扩容操作
    // sizeCtl = -1,表示正在初始化中
    // sizeCtl = -n,表示 n - 1个线程正在进行扩容
    // sizeCtl >  0,初始化和扩容中需要使用的容量
    // sizeCtl =  0,默认值,使用默认值进行初始化
    private transient volatile int sizeCtl;
    
    // 扩容下另一个表的索引
    private transient volatile int transferIndex;

    // 旋转锁,扩容或者创建counterCells时使用
    private transient volatile int cellsBusy;

    // counterCell数组
    private transient volatile CounterCell[] counterCells;

    // 视图
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值