分段锁思想是用多把小锁替代一把大锁,按访问维度逻辑隔离,锁粒度与保护数据范围对齐;如按业务域拆分独立缓存实例(UserCache、ConfigCache、TokenCache),或按key哈希前缀二级分片,并避免全局锁操作、慎用遍历和computeIfAbsent,结合读写分离提升并发性能。

分段锁思想的核心是把“一把大锁”换成“多把小锁”,让不同线程操作不同数据时互不干扰。它不是靠物理分段,而是按访问维度做逻辑隔离——锁的粒度要和实际被保护的数据范围对齐。
按业务域拆分独立缓存实例
避免所有数据塞进同一个 ConcurrentHashMap。比如用户会话、系统配置、临时令牌这三类数据访问模式差异大、生命周期不同,混在一起容易形成热点桶竞争。
- 分别定义 UserCache、ConfigCache、TokenCache,每个都持有一个独立的 ConcurrentHashMap 实例
- 这样写操作只锁定各自 map 的对应桶,跨域访问完全无锁冲突
- 清理逻辑也隔离:比如 TokenCache 可配 TTL 自动过期,不影响 ConfigCache 的稳定性
按 key 哈希前缀做二级分片
当单个缓存实例仍面临高并发写压力(如百万级用户 ID 写入),可手动模拟分段机制,进一步分散锁点。
- 取 key.hashCode() & 0xF 得到 0–15 共 16 个分片号
- 维护一个大小为 16 的 ConcurrentHashMap 数组:ConcurrentHashMap<K, V>[] shards
- put 时先算分片号,再操作对应 shard,锁只作用于该子 map 的桶内节点
- 注意:分片数不宜过多(一般 2ⁿ),否则哈希分布不均或内存开销上升
避免全局锁操作破坏并发性
即使底层用了 ConcurrentHashMap,不当使用仍会引入隐式全局锁。
立即学习“Java免费学习笔记(深入)”;
- 不要用 keySet() / values() / entrySet() 遍历全量数据——这些操作虽不加锁,但可能触发扩容或结构重排,间接影响并发写
- 清理过期数据别用定时线程反复 scan 整个 map,改用时间轮或每个分片自带的 LRU 队列
- 慎用 computeIfAbsent 做复杂初始化:若内部含 I/O 或耗时计算,应提前移出同步块,只在真正需要写入时加锁
读写分离 + 细粒度写锁协同使用
ConcurrentHashMap 的 get 是无锁的 volatile 读,但 put/remove 默认只锁单个桶;若业务读多写少,可叠加读写锁进一步释放读并发。
- 对整个缓存结构加 ReentrantReadWriteLock,读操作用 readLock,写操作用 writeLock
- 适用于配置类缓存:读频率极高,写仅发生在发布变更时
- 注意不能和 ConcurrentHashMap 原生的桶锁混用——ReadWriteLock 是保护整个缓存视图,不是替代桶级细粒度锁



















