悲观锁(Pessimistic Locking)是一种传统的并发控制机制,假设数据在访问过程中极有可能被其他线程修改,因此在数据访问前先加锁,确保同一时间只有一个线程能操作数据。这种策略通过牺牲并发性能来保证数据的一致性。
核心原理
独占资源
线程在访问数据前先获取锁,其他线程必须等待锁释放才能访问。常见实现包括:- 数据库层面:行锁、表锁。
- 编程语言层面:
synchronized关键字、ReentrantLock。
锁的粒度
- 细粒度锁:如行锁,并发度高但实现复杂。
- 粗粒度锁:如表锁,实现简单但可能导致大量线程阻塞。
悲观锁的优缺点
优点
- 强一致性:确保数据在任何时刻只能被一个线程修改。
- 简单易用:多数编程语言和数据库提供内置支持。
缺点
- 性能开销大:线程阻塞导致上下文切换频繁。
- 可能导致死锁:多个线程循环等待对方释放锁。
- 不适用于读多写少场景:读操作也会被阻塞,浪费资源。
实现方式
1. 数据库悲观锁
行锁:
SELECT * FROM table WHERE id = ? FOR UPDATE; -- MySQL- 事务提交前,其他线程无法修改该行数据。
表锁:
LOCK TABLES table WRITE; -- MySQL- 锁表期间,其他线程无法读写该表。
2. Java语言实现
synchronized关键字:
public class SynchronizedExample { private final Object lock = new Object(); public void writeData() { synchronized (lock) { // 临界区代码,同一时间仅一个线程执行 } } }ReentrantLock:
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); public void writeData() { lock.lock(); try { // 临界区代码 } finally { lock.unlock(); // 必须在finally中释放锁 } } }
悲观锁的典型应用场景
- 写操作频繁:如库存扣减、账户转账。
- 数据一致性要求高:如金融系统交易处理。
- 长事务操作:如跨多个资源的复杂业务流程。
与乐观锁的对比
| 特性 | 悲观锁 | 乐观锁 |
|---|---|---|
| 加锁时机 | 访问数据前 | 更新数据时 |
| 实现方式 | synchronized、数据库锁 |
CAS、版本号机制 |
| 适用场景 | 写多冲突多、长事务 | 读多写少、冲突少 |
| 线程状态 | 阻塞等待锁释放 | 无阻塞,冲突时重试 |
| 一致性保证 | 强一致性 | 弱一致性(冲突时可能失败) |
注意事项
死锁预防
- 按相同顺序获取锁,设置锁超时时间。
- 使用
ReentrantLock.tryLock()避免死锁。
锁粒度优化
- 避免在大方法上加锁,减小锁的范围。
性能监控
- 高并发场景下,通过工具(如JStack)监控锁竞争情况。
Java中的悲观锁工具
synchronized关键字
- 隐式锁,由JVM自动释放。
ReentrantLock
- 显式锁,支持公平锁、可中断锁、条件变量。
ReadWriteLock
- 读写分离锁,允许多个线程同时读,但写时独占。
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockExample { private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); public void readData() { rwLock.readLock().lock(); try { // 允许多个线程同时读 } finally { rwLock.readLock().unlock(); } } public void writeData() { rwLock.writeLock().lock(); try { // 同一时间仅一个线程写 } finally { rwLock.writeLock().unlock(); } } }
总结
悲观锁通过提前加锁确保数据一致性,适用于写操作频繁、冲突严重的场景。但在高并发读场景下,过度使用会导致性能瓶颈。现代系统通常结合悲观锁与乐观锁,根据业务特点选择合适的并发控制策略,以平衡性能与数据安全。