Spring中SimpleAliasRegistry的removeAlias方法加synchronized锁的必要性分析
核心原因:锁的作用是全局同步,而非保护单个remove操作
你说的没错,ConcurrentHashMap的单个remove操作本身就是原子线程安全的,完全不需要额外加锁。这里加synchronized的根本目的是和类里其他用aliasMap当锁的方法对齐,实现全局互斥,保证跨方法操作的状态一致,具体有两个原因:
1. 避免破坏读操作的一致性
SimpleAliasRegistry里的resolveAliases、registerAlias都是复合操作,内部都用synchronized(aliasMap)加了锁:
比如resolveAliases要遍历别名链做解析,加锁就是为了保证遍历过程中aliasMap的内容不会变,拿到完整一致的结果。
如果removeAlias不加锁,就会出现时序问题:线程A拿着锁正在解析别名链,线程B直接调用无锁的remove删了某个别名,导致A遍历到一半别名链断裂,直接解析出错误结果。
2. 维护统一的修改同步边界
官方这次修复的核心逻辑就是:所有对aliasMap的修改(增、删、改),都必须在aliasMap这把锁的保护下执行。这样只要是拿着这把锁的读操作,读到的一定是修改操作要么全完成、要么全没做的一致状态,不会出现中间态。
要是removeAlias不加锁,它的修改就会跳出这个同步规则,直接把整个类的一致性保障废掉。
移除synchronized会引发的问题
- 并发场景下
resolveAliases会频繁返回不符合预期的结果,比如明明存在的别名解析为空、解析出错误的规范名称,极端情况还会因为别名链被意外修改出循环而触发死循环 - 依赖别名存在性判断的业务逻辑会偶发报错:比如刚校验完别名存在,还没执行后续操作,别名就被无锁的remove操作删掉,触发空指针或非法状态异常
内容的提问来源于stack exchange,提问作者CHANist
相关产品推荐
相关产品推荐

