java8 ConcurrentHashMap 桶级别锁实现机制

Java 8 ConcurrentHashMap 桶级别锁实现机制

Java 8 中的 ConcurrentHashMap 抛弃了分段锁设计,采用了更细粒度的桶级别锁(bucket-level locking)实现,这是其并发性能提升的关键。下面详细解析其实现原理:

1. 基本实现原理

桶级别锁的核心思想是:只锁定当前操作的哈希桶(链表或树的头节点),而不是整个表或某个段。

关键实现方式:

  • CAS + synchronized 组合控制
  • 锁对象是每个桶的头节点
  • 读操作完全无锁(volatile读)
  • 写操作仅在必要时加锁

2. 具体实现细节

2.1 锁获取方式

// putVal方法中的锁获取片段
synchronized (f) { // f是桶的头节点
    if (tabAt(tab, i) == f) { // 双重检查
        // 执行插入操作...
    }
}

2.2 锁的获取条件

  1. 桶不为空时才会加锁
  2. 只锁住当前桶的头节点
  3. 通过 synchronized 关键字实现(JVM优化后的偏向锁/轻量级锁)

3. 实现步骤分解

3.1 插入元素时的锁控制流程

  1. 计算 key 的哈希并定位桶位置
  2. 如果桶为空,使用 CAS 无锁插入
    if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))
        break;
    
  3. 如果桶不为空,则锁住头节点:
    synchronized (f) {
        // 处理链表或树
    }
    

3.2 锁的细粒度验证

synchronized (f) {
    if (tabAt(tab, i) == f) { // 再次确认当前节点仍是头节点
        // 实际处理逻辑
    }
}

这种双重检查确保:

  • 防止在获取锁期间桶已被其他线程修改
  • 保证操作的原子性

4. 技术优势

  1. 更高的并发度

    • 理论上并发度 = 哈希桶数量(默认16 → 可能成千上万)
  2. 更低的锁竞争

    • 不同桶的操作完全并行
    • 只有哈希冲突时才会竞争
  3. 自适应锁优化

    • JVM 会根据竞争情况自动升级锁(偏向锁→轻量级锁→重量级锁)
  4. 与扩容协同

    • 扩容时通过 ForwardingNode 保证操作可以继续

5. 与 Java 7 分段锁对比

特性Java 7 分段锁Java 8 桶级别锁
锁粒度段(默认16)单个桶
锁实现ReentrantLocksynchronized
读操作需要段锁完全无锁
扩容段独立扩容整体协同扩容
冲突处理链表链表+红黑树

6. 实际代码示例

6.1 链表情况下的锁应用

// putVal方法片段
synchronized (f) {
    if (tabAt(tab, i) == f) {
        if (fh >= 0) { // 普通链表节点
            binCount = 1;
            for (Node<K,V> e = f;; ++binCount) {
                // 遍历链表...
                if ((e = e.next) == null) {
                    e.next = new Node<K,V>(hash, key, value, null);
                    break;
                }
            }
        }
    }
}

6.2 树情况下的锁应用

else if (f instanceof TreeBin) {
    Node<K,V> p;
    binCount = 2;
    if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {
        oldVal = p.val;
        if (!onlyIfAbsent)
            p.val = value;
    }
}

7. 关键设计考量

  1. synchronized 优化

    • Java 6 后 synchronized 性能已大幅提升
    • JVM 会根据竞争情况自动优化
  2. CAS 失败回退

    • 当 CAS 插入失败(竞争)时才使用锁
  3. 死锁避免

    • 只按固定顺序获取单个锁
    • 不会出现交叉锁请求
  4. 内存可见性

    • 通过 volatile 变量保证
    • setTabAt/tabAt 使用 Unsafe 保证原子性

这种桶级别锁设计使得 ConcurrentHashMap 在 Java 8 中实现了:

  • 更高的并发吞吐量
  • 更低的操作延迟
  • 更平滑的性能曲线
  • 更好的可扩展性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值