你们用 ConcurrentHashMap 做过本地缓存或并发统计吗?它怎么保证并发安全,使用时还要注意什么?
我的判断
ConcurrentHashMap 适合并发读写和单 key 原子更新,但它不是带过期、容量控制和加载保护的完整缓存。
我们会用它保存生命周期明确、规模可控的本地路由表,或者做短周期并发统计。读取通常不加全局锁,更新通过 CAS 和桶级同步控制竞争;计数会用 compute、merge,热点统计则用 LongAdder,避免“先 get 再 put”这种复合操作丢更新。
counts.computeIfAbsent(key, ignored -> new LongAdder()).increment();
computeIfAbsent 的加载函数不能做慢 RPC,也不能递归修改同一个 key,否则会把竞争和故障放大。多个 key 之间的一致性它也保证不了,这时需要显式锁、不可变快照或重新设计状态边界。
如果需求包含 TTL、最大容量、淘汰、刷新和防缓存击穿,我会直接用 Caffeine,而不是在 ConcurrentHashMap 外再拼一套定时清理。上线后重点看 key 数、命中率、加载耗时和堆占用。
容易答偏踩坑误区
- 线程安全等于所有操作都原子。
containsKey后再put仍然有竞态。 - 在计算函数里调用慢下游。 同 key 请求会排队,故障时很容易拖垮线程。
- 当成无限缓存。 没有容量和过期策略,最终会变成堆内存问题。