在并发编程和数据库开发中“锁”是一个绕不开的话题。其中悲观锁是一种非常经典、也非常重要的并发控制机制。本文将从概念、原理、实现方式、使用场景和代码示例多个角度介绍什么是悲观锁。文章目录一、什么是悲观锁1. 悲观锁的定义2. 通俗理解二、悲观锁的工作原理三、悲观锁的主要实现方式1. 数据库层面的悲观锁2. Java 中的悲观锁synchronized3. ReentrantLock显式锁四、悲观锁 vs 乐观锁五、悲观锁的典型使用场景1. 高冲突写场景2. 对一致性要求极高的系统六、实战案例库存扣减1. 错误示例无锁2. 悲观锁实现七、悲观锁的优缺点分析优点缺点八、使用悲观锁的注意事项1. 控制锁的粒度2. 避免死锁3. 减少锁持有时间九、面试常见问题1. 什么是悲观锁2. 什么时候用悲观锁3. 悲观锁一定安全吗参考一、什么是悲观锁1. 悲观锁的定义悲观锁Pessimistic Lock是一种对并发冲突持“悲观态度”的锁机制。它的核心思想是总是认为并发操作一定会发生冲突因此在操作数据前先加锁。只要我在用数据就不允许别人修改。2. 通俗理解可以把悲观锁理解为“先上锁再干活”“宁可等也不乱”就像公共洗手间进去先反锁出来再开门。别人只能等你用完。二、悲观锁的工作原理悲观锁的基本流程如下线程/事务申请锁获取成功后进入临界区执行业务操作提交事务并释放锁其他线程继续执行流程示意线程A加锁 → 操作 → 解锁 线程B等待 → 加锁 → 操作 → 解锁本质上同一时间只允许一个线程操作共享资源。三、悲观锁的主要实现方式1. 数据库层面的悲观锁在数据库中悲观锁主要通过SELECT ... FOR UPDATE实现。示例MySQLSELECT*FROMaccountWHEREid1FORUPDATE;特点查询时直接加行锁事务提交后释放其他事务无法修改该行适用于高并发写场景。2. Java 中的悲观锁synchronizedsynchronized是 Java 中最经典的悲观锁实现。示例publicsynchronizedvoidadd(){count;}特点自动加锁和释放阻塞式等待性能稳定3. ReentrantLock显式锁ReentrantLock属于更灵活的悲观锁。示例LocklocknewReentrantLock();lock.lock();try{count;}finally{lock.unlock();}优势可中断可超时支持公平锁四、悲观锁 vs 乐观锁理解悲观锁必须对比乐观锁。对比维度悲观锁乐观锁并发态度悲观乐观是否加锁是否通常冲突处理阻塞等待重试性能稳定高并发下更优实现方式锁机制CAS / 版本号一句话总结冲突多用悲观锁冲突少用乐观锁。五、悲观锁的典型使用场景1. 高冲突写场景例如库存扣减账户转账秒杀下单这些场景下写多、冲突多、数据敏感。适合使用悲观锁。2. 对一致性要求极高的系统例如金融系统支付系统订单系统不能出现脏数据宁可慢一点。六、实战案例库存扣减1. 错误示例无锁if(stock0){stock--;}可能导致超卖。2. 悲观锁实现publicsynchronizedbooleanreduceStock(){if(stock0){stock--;returntrue;}returnfalse;}保证同一时间只有一个线程执行。七、悲观锁的优缺点分析优点实现简单数据安全性高不容易出错逻辑清晰缺点并发性能较差容易产生阻塞可能导致死锁吞吐量受限八、使用悲观锁的注意事项1. 控制锁的粒度锁太大性能差锁太小复杂度高建议尽量缩小锁范围。2. 避免死锁常见死锁原因锁顺序不一致嵌套锁建议统一加锁顺序。3. 减少锁持有时间锁内代码越少越好。不要在锁里做网络请求IO 操作复杂计算九、面试常见问题1. 什么是悲观锁答操作前先加锁假设一定发生冲突。2. 什么时候用悲观锁答高并发写、多冲突、强一致场景。3. 悲观锁一定安全吗答逻辑正确前提下安全但可能死锁。参考悲观锁和乐观锁 - 迷失的布莱克 - 博客园Java并发常见面试题总结中