看面经看到 JDK7 的 HashMap 并发 put 会导致 CPU 100%,一直没搞懂为什么扩容会产生环形链表。
有没有大佬能画个图讲讲?最好能说说 JDK8 之后为什么修复了。
看面经看到 JDK7 的 HashMap 并发 put 会导致 CPU 100%,一直没搞懂为什么扩容会产生环形链表。
有没有大佬能画个图讲讲?最好能说说 JDK8 之后为什么修复了。
核心是 JDK7 扩容用的头插法,多线程同时 resize 时,节点 A.next = B 和 B.next = A 可能同时发生,形成环。
JDK8 改成尾插法 + 高位拆分,保持了原有顺序,所以不会出现环形链表。但 JDK8 的 HashMap 仍然不是线程安全的,会丢数据,并发场景请用 ConcurrentHashMap。
补充一张图(文字版):
扩容前:A -> B -> null\n线程1 挂起时:B -> A\n线程2 完成后:A -> B -> A (成环)
遍历到这个桶就是死循环。
明白了!感谢两位,那 ConcurrentHashMap 在 JDK8 中是怎么保证安全的?
JDK8 的 CHM 用 synchronized 锁住单个桶的头节点 + CAS 插入,锁粒度从 Segment 降到桶级别,并发度更高。