问答题1009/1053什么是悲观锁?什么是乐观锁?

难度:
2021-11-02 创建

参考答案:

悲观锁乐观锁是两种常见的锁策略,用于在并发编程中处理多线程对共享资源的访问。它们的主要区别在于对资源访问冲突的假设和应对方式不同。

1. 悲观锁(Pessimistic Lock)

悲观锁的核心思想是:认为在多线程并发环境中,资源竞争是频繁的,因此每次访问共享资源时都需要加锁,避免冲突。如果线程在访问资源时发现资源被其他线程占用,它会一直等待,直到获得锁。

特点:

  • 假设资源冲突发生的概率较高,因此每次访问共享资源时都加锁。
  • 一般通过显式加锁来实现,比如使用 synchronizedReentrantLock
  • 由于加锁,其他线程不能同时访问资源,避免了数据的不一致性,但会造成线程阻塞。

典型实现:

  • synchronized(Java)和 ReentrantLock(Java)都可以实现悲观锁。
  • 在数据库中,悲观锁通常使用数据库事务中的锁机制(如行锁、表锁)来实现。

优缺点:

  • 优点:通过加锁避免了资源冲突和数据不一致性,适用于竞争激烈、冲突多的场景。
  • 缺点:加锁可能导致性能瓶颈,尤其是高并发时,线程可能会长时间阻塞,降低系统吞吐量。

2. 乐观锁(Optimistic Lock)

乐观锁的核心思想是:认为资源竞争不频繁,因此在访问共享资源时,不加锁,而是在操作结束时检查是否有其他线程修改了资源。如果没有冲突,则操作成功;如果有冲突,则重试或回滚操作。

特点:

  • 假设资源冲突发生的概率较低,因此不加锁,只有在提交时才检查是否有并发冲突。
  • 通常通过版本号或时间戳机制来判断是否有其他线程修改了资源。
  • 如果资源被修改,乐观锁会要求线程重新尝试操作。

典型实现:

  • 版本号机制:每次对数据进行修改时,会检查版本号是否一致,如果版本号一致,表示数据没有被其他线程修改过,操作成功;如果版本号不一致,则表示发生了并发冲突,线程需要重新尝试。
    • 例如,CAS(Compare-And-Swap) 是一种乐观锁的实现方式。
  • 数据库中的乐观锁:使用 SELECT ... FOR UPDATE 来查询数据,并检查是否有并发冲突。

优缺点:

  • 优点:避免了加锁带来的性能开销,适用于冲突较少的场景,能够提高系统的并发性。
  • 缺点:如果冲突较多,重试机制可能导致性能问题。并且,乐观锁需要额外的冲突检测和回滚机制,增加了实现的复杂性。

比较

特性悲观锁乐观锁
锁定方式每次访问时加锁访问时不加锁,操作后检查
锁的粒度较大(可能是整个数据或资源)较小(通常是数据版本或时间戳)
适用场景数据冲突较多,竞争激烈数据冲突较少,竞争较轻
性能高并发时可能导致性能瓶颈高并发时性能更好,避免了加锁
典型实现synchronizedReentrantLockCAS,版本号控制

最近更新时间:2024-12-09