JDK 8 的 ConcurrentHashMap 两种思想都用了:
CAS → 乐观锁思想
synchronized → 悲观锁思想
乐观锁是什么?
乐观锁的思想是:
我觉得别人不会和我冲突,我先尝试修改;真冲突了再重试。
比如 ConcurrentHashMap 发现桶为空:
table[i] = null
线程A:想放 Node A
线程B:想放 Node B通过 CAS:
线程A:CAS(null → A) → 成功
线程B:CAS(null → B)
↓
发现已经不是 null
↓
失败,重新尝试它不会提前把位置锁住。
所以:
CAS 是典型的乐观并发控制方式:先尝试,冲突了再处理。
悲观锁是什么?
悲观锁的思想是:
我认为别人很可能和我同时修改,所以我先把资源锁住,其他线程先等着。
ConcurrentHashMap 桶不为空时:
table[i]
↓
A → B → C
🔒执行:
synchronized (A) {
// 修改当前桶
}线程 A 拿到锁:
线程A → 🔒 → 修改链表
线程B → 等待……所以 synchronized 属于典型的悲观锁机制。
一句话区分
乐观锁:
“应该没人跟我抢,我先试试”
↓
CAS
悲观锁:
“肯定有人跟我抢,我先锁起来”
↓
synchronized / Lock因此面试问:
ConcurrentHashMap 用的是悲观锁还是乐观锁?
回答:
JDK 8 ConcurrentHashMap 两者都有使用。对于一些简单竞争场景,例如空桶插入,会通过 CAS 这种乐观并发方式完成;对于已经存在节点的桶,需要修改链表或红黑树时,会使用 synchronized 进行互斥,属于悲观锁机制。
口诀就是:
CAS:先试,失败重来——乐观。
synchronized:先锁,再操作——悲观。