https://mp.weixin.qq.com/s/FGjppy6yTLdCKD7oQQpXWA

技术选型

这次研究让我明白了,技术选型必须结合具体业务场景。阿里为了应对超大规模、高并发、高可用的场景,重写 HashMap 并做了这些优化:

阿里的业务特点:

超大规模:单机存储亿级数据

高并发:双11期间 QPS 百万级

低延迟:99.9% 请求要求 <10ms

高可用:不能因为扩容影响服务

JDK ConcurrentHashMap 的局限性:

扩容时全量 rehash,影响响应时间

内存布局不够紧凑,浪费空间

分段锁粒度不够细,高并发下仍有瓶颈

public class OptimizedCache<K, V> {
    private final Map<K, V> hotData;
    private final Map<K, V> coldData;
    public OptimizedCache(int hotSize, int coldSize) {
        this.hotData = new ConcurrentHashMap<>(hotSize, 0.9f);
        this.coldData = new ConcurrentHashMap<>(coldSize, 0.75f);
    }
    public V get(K key) {
        V value = hotData.get(key);
        if (value != null) return value;
        value = coldData.get(key);
        if (value != null) {
            promoteToHot(key, value);
        }
        return value;
    }
}

带着疑问,我开始研究阿里的开源项目,发现了几个有趣的优化方案:

  1. 分段锁的进化版
    阿里内部对 HashMap 进行了分段锁优化,每个段独立扩容,避免全局锁的瓶颈:


public class SegmentedHashMap<K, V> {
    private final Segment<K, V>[] segments;
    private final int segmentMask;
    public V put(K key, V value) {
        int hash = hash(key);
        int segIndex = (hash >>> 28) & segmentMask;
        return segments[segIndex].put(key, value, hash);
    }
    static class Segment<K, V> {
        private volatile HashEntry<K, V>[] table;
        // ...
    }
}
  1. 内存预分配策略
    基于业务特点,阿里还进行了内存预分配,避免了频繁的扩容和对象创建:


public class PreSizedConcurrentMap<K, V> extends ConcurrentHashMap<K, V> {
    public PreSizedConcurrentMap(int expectedSize, float loadFactor) {
        super(calculateInitialCapacity(expectedSize, loadFactor), loadFactor);
    }
    private static int calculateInitialCapacity(int expected, float lf) {
        return (int) Math.ceil(expected / lf);
    }
}
文档更新时间: 2025-11-27 21:13   作者:admin