一文彻底理解乐观锁与悲观锁

一文彻底理解乐观锁与悲观锁
最新回答
纯家小可爱

2026-07-09 11:23:37

一文彻底理解乐观锁与悲观锁

一、什么是乐观锁?

乐观锁(Optimistic Locking)相对于悲观锁而言,采取更加宽松的加锁机制。它假设在数据处理过程中,不会发生冲突,因此不会直接锁定数据资源。乐观锁大多基于数据版本(version)记录机制实现,即为数据增加一个版本标识。在更新数据时,会检查当前数据的版本号是否与读取时一致,如果一致则进行更新,否则认为数据已被其他事务修改,更新失败。

二、乐观锁实现方式

  1. 版本号机制:在数据库表中增加一个version字段,每次更新数据时,版本号加1。提交更新时,检查当前版本号是否与读取时一致,一致则更新成功,否则更新失败。
  2. CAS(Compare and Swap)机制:CAS需要三个参数,内存地址V、旧的预期值A和新值B。只有当V的值等于A时,才会将V的值改为B。CAS机制常用于无锁算法中,如java.util.concurrent包中的原子变量。

三、乐观锁优缺点

优点:

  • 提高了系统的并发性能,因为大部分时间都不需要锁定资源。
  • 减少了数据库的开销,特别是在长事务中。

缺点:

  • 在高冲突场景下,应用会不断尝试加锁,反而会影响系统性能。
  • CAS机制存在ABA问题,即值在比较期间被修改后又改回原值,但版本已发生变化。

四、乐观锁适用场景

乐观锁适合读多写少的场景,这样冲突就很少发生,降低了加锁的成本。例如,在电商网站的商品浏览场景中,商品信息的读取操作远多于修改操作。

五、什么是悲观锁?

悲观锁(Pessimistic Locking)具有强烈的独占和排他特性。它假设在数据处理过程中,会发生冲突,因此会锁定数据资源,以防止其他事务对数据进行修改。悲观锁的实现往往依靠数据库提供的锁机制,如MySQL的for update语句。

六、悲观锁实现方式

  1. Synchronized和Lock:Java中的Synchronized关键字和Lock接口提供了悲观锁的实现方式,用于确保在多线程环境下对共享资源的独占访问。
  2. 数据库锁机制:如MySQL的for update语句,会对查询到的数据加排他锁,其他事务无法对该数据进行修改。

七、悲观锁优缺点

优点:

  • 保证了多线程下顺序读写,防止脏数据产生。
  • 在高冲突场景下,能够确保数据的正确性。

缺点:

  • 并发场景下性能显著下降,因为需要锁定资源。
  • 可能导致死锁问题,如果多个事务相互等待对方释放锁。

八、悲观锁适用场景

悲观锁适合读少写多的场景,这种场景下冲突多,因此悲观锁能够确保数据的正确性和一致性。例如,在电商网站的库存扣减场景中,库存的修改操作远多于读取操作,此时使用悲观锁能够防止超卖现象的发生。

总结:

  • 乐观锁和悲观锁是两种不同的并发控制策略。
  • 乐观锁基于数据版本记录机制实现,适合读多写少的场景;悲观锁依靠数据库锁机制实现,适合读少写多的场景。
  • 乐观锁的优点是提高并发性能和减少数据库开销,缺点是在高冲突场景下会影响系统性能;悲观锁的优点是保证数据正确性和一致性,缺点是并发性能下降和可能导致死锁问题。
  • 在实际应用中,应根据具体场景选择合适的锁策略。