一个程序员应该知道的各种锁
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自动)