1. 悲观锁 vs 乐观锁(心态问题)
-
悲观锁:觉得肯定有人抢厕所,进去就反锁门(加锁),用完再开。
→ Java里的synchronized和ReentrantLock都是这种。安全,但慢。 -
乐观锁:觉得没人抢,不锁门,但上厕所时盯着门把手(版本号/时间戳),如果发现被人动过(冲突),就重试。
→ Java里的 CAS(比较并交换) 就是这种,比如AtomicInteger。快,但冲突多时会反复重试。
2. 公平锁 vs 非公平锁(排队问题)
-
公平锁:先来后到,乖乖排队。
→new ReentrantLock(true)。公平,但效率低(大家都得排队)。 -
非公平锁:新来的可以插队,如果锁刚好释放,它就直接抢。
→synchronized和默认的ReentrantLock都是非公平。效率高,但可能导致某些线程饿死(一直抢不到)。
3. 可重入锁(同一个人的多次进入)
- 你进了厕所A,发现里面还有个小隔间B,你能直接进B,不用再掏钥匙。
→synchronized和ReentrantLock都支持。同一个线程可以多次获取同一把锁,防止自己把自己卡死。
4. 读写锁(分情况管理)
- 厕所分蹲位(写锁)和洗手池(读锁)。
- 多人同时洗手(读)没问题。
- 但有人蹲坑(写)时,别人既不能蹲也不能洗手(全阻塞)。
→ReentrantReadWriteLock。适合读多写少的场景。
5. 共享锁 vs 排他锁(权限级别)
- 排他锁(写锁):厕所门一锁,谁也别进。
- 共享锁(读锁):可以多人同时看同一份文件(但不能改)。
→ 读写锁就是共享/排他的典型实现。
6. 偏向锁 → 轻量级锁 → 重量级锁(锁升级,JVM自动优化)
这是 synchronized 的底层升级过程(为了性能):
- 偏向锁:厕所只认你一个人,你每次来都不用掏钥匙(无竞争)。
- 轻量级锁:偶尔有别人来,你们用“自旋”方式(原地转圈等)抢,不挂起线程(省资源)。
- 重量级锁:竞争激烈,排队挂起(操作系统介入,慢)。
→ 这是JVM自动做的,你不用管,但知道它存在即可。
7. 自旋锁(不睡觉,死等)
- 厕所被占,你不去排队睡觉,而是在门口原地转圈(循环检查),等它释放。
→ 适合持有锁时间很短的情况,避免线程挂起/唤醒的开销。Java里的CAS就是自旋思想。
8. 分段锁(分块管理)
- 一个大厕所分成多个小隔间,锁只锁其中一间,不影响其他间。
→ConcurrentHashMap早期就是用分段锁,提升并发度(现在改用CAS+细粒度锁了)。
一张图总结(按使用场景选):
| 场景 | 推荐锁 |
|---|---|
| 简单同步,代码少 | synchronized |
| 需要可中断、超时、公平等灵活功能 | ReentrantLock |
| 读多写少(如缓存) | ReentrantReadWriteLock |
| 计数器、自增等简单操作 | AtomicXXX(乐观锁) |
| 追求极致性能,竞争不激烈 | 偏向锁/轻量级锁(JVM自动) |