Java中嵌套ConcurrentHashMap的使用及线程安全选型疑问
首先明确结论:
如果你的业务中需要对内层哈希表做并发读写操作,必须选ConcurrentHashMap<String, ConcurrentHashMap<String, String>>;如果内层哈希表初始化后就只做读操作、不再修改,ConcurrentHashMap<String, HashMap<String, String>>可以临时用,但绝非最优解。
两者的核心区别如下:
线程安全覆盖范围不同
ConcurrentHashMap<String, HashMap<String, String>>只有外层容器是线程安全的,内层的HashMap还是非线程安全的。当多个线程同时操作同一个内层HashMap(比如新增键值对、修改值、扩容),依然会出现数据错乱、JDK7及以前版本的死循环,或者触发fail-fast异常。
而ConcurrentHashMap<String, ConcurrentHashMap<String, String>>的外层和内层都实现了线程安全,所有层级的并发读写操作都能得到可靠保障。适用场景差异
前者仅适合极端场景:内层哈希表是静态的(初始化后完全不修改,只做查询),只有外层哈希表存在并发增删键值对的需求。但这种场景非常少见,一旦后续业务调整需要修改内层数据,立刻会引入线程安全隐患。
后者是绝大多数嵌套哈希表并发场景的正确选择——只要内层哈希表需要进行并发的增删改查,就必须用这种全层级线程安全的结构。性能与风险的平衡
两者的外层都用ConcurrentHashMap的高效并发机制(JDK7分段锁、JDK8+ CAS+锁粒度细化),但前者的内层HashMap没有任何并发控制,并发修改时风险极高;后者的内层同样采用ConcurrentHashMap的优化实现,在保证线程安全的同时,能维持较好的并发性能。
内容的提问来源于stack exchange,提问作者Jackzenko

