多线程环境下get方法未同步的LinkedHashMap会引发内存泄漏吗?
问题结论
首先明确回答你的两个疑问:
- get方法未加
synchronized同步的情况下,确实存在内存泄漏的风险,你描述的并发场景下可能出现"b"永远无法被回收的情况。 - 内存泄漏的核心原因是非线程安全容器的并发读写导致内部结构损坏,具体分析如下:
详细分析
你用到的LinkedHashMap本身是不保证线程安全的,你的代码里仅对put、remove加了同步锁,但是get方法没有同步,就会出现「并发写+并发读」的违规使用场景,会触发两类问题:
- 内存可见性问题:
synchronized关键字会保证方法执行完成后,修改被强制刷回主存;但没有加同步的get方法没有主存同步的义务,thread2可能长期读取自身工作内存里的旧缓存副本,拿到已经被删除的"b"值。这种情况不算严格的永久内存泄漏,只要所有持有旧副本的线程退出,引用就会被释放。 - 内部结构损坏(永久内存泄漏的核心原因):
remove操作执行时会修改LinkedHashMap内部的哈希桶、双向链表结构,如果修改过程中get操作并发执行,很可能破坏内部指针关系,导致已经被移除的Entry节点仍然被容器的内部数据结构持有引用。这种情况下只要Cache实例不被回收,"b"的引用就会被Cache一直持有,永远无法被垃圾回收器回收。
测试场景对应结论
你描述的场景下有概率出现Cache持有"b"引用、"b"永远无法被GC的情况,概率大小取决于CPU调度、JVM版本等多方面因素,属于典型的并发编程里的偶发问题,一旦出现很难排查。
修复方案
最简单的修复方式是给get方法也加上synchronized关键字,保证所有对cache的操作都持有同一把锁;如果对读性能要求较高,也可以直接用ConcurrentHashMap代替LinkedHashMap,或者使用现成的线程安全缓存实现。
内容的提问来源于stack exchange,提问作者user3409583
相关产品推荐
相关产品推荐

