简述悲观锁和乐观锁

概念

  • 悲观锁: 悲观锁假设在操作数据时,冲突是常见的,因此它在数据操作前就加锁,防止其他线程或进程访问。这种锁通常在事务开始时就锁定资源,直到事务结束才释放。
  • 乐观锁: 乐观锁假设在操作数据时,冲突是少见的。它不通过加锁来控制数据访问,而是通过数据版本控制或时间戳来确保数据在读取后未被其他进程修改。

实现

  • 悲观锁: 通常通过数据库的锁机制实现,如行锁、表锁等。在编程中,可以使用synchronized关键字(Java)、lock对象(C#)等来实现。
  • 乐观锁: 通常使用数据版本(version)或时间戳来实现。每次读取数据时,都会获取版本号或时间戳,更新数据时检查版本号或时间戳是否发生变化,如果没有变化,则进行更新并增加版本号或更新时间戳。

性能

  • 悲观锁: 由于需要频繁地加锁和解锁,可能会在高并发情况下引起性能瓶颈。
  • 乐观锁: 在冲突较少的情况下,性能通常优于悲观锁,因为它不需要加锁,减少了锁的开销。

适用场景

  • 悲观锁: 适用于写操作多于读操作,或者数据冲突可能性较高的场景。
  • 乐观锁: 适用于读操作多于写操作,或者数据冲突可能性较低的场景。

冲突处理

  • 悲观锁: 如果发生冲突,其他线程会被阻塞,直到锁被释放。
  • 乐观锁: 如果检测到冲突(如版本号或时间戳不一致),通常会重新读取数据并重试操作,或者抛出异常。

死锁风险

  • 悲观锁: 由于锁的存在,如果多个线程互相等待对方释放锁,可能会产生死锁。
  • 乐观锁: 由于没有显式的锁,死锁的风险较低,但需要合理处理冲突。

redis可以做锁,可以用redisson+aop的形式。然而,实际生产环境中, redis都是集群或者sentinel部署的,我个人只建议redLock的做法。

其实用锁都是偏向于低性能的做法了, 更建议用zookeeper,而不是redis。


Comments

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注