在学习Java时,我们常常会听到乐观锁和悲观锁,那么什么是乐观锁,什么是悲观锁呢?
我们先来看一下如下情况:
乐观锁就是先更新再检验,而悲观锁就是先进行保护然后再修改。
为什么要保护?什么是保护?
我们设想如下情况
A=100
现在有两个线程T1和T2
T1要A-50
T2要A-50
T1和T2并发执行。
如果T1先取出来,在T1还没进行更改的时候T2就取了出来那么就会造成数据错误。
简单的了解了两个锁的内容,接下里我们给出详细的解释:
乐观锁和悲观锁是并发控制的两种不同策略,用于处理多个并发操作对共享资源的访问问题。
- 乐观锁:
乐观锁假设多个事务或线程之间很少发生冲突,因此在读取数据时,不会立即上锁。相反,它会在事务提交时检查数据是否被其他事务修改。常见的实现方式是使用版本号或时间戳来追踪数据的变化。当一个事务要更新数据时,它首先会检查数据的版本号或时间戳是否与事务开始时相同,如果相同则更新数据并增加版本号/时间戳。如果检查失败,表示数据已被其他事务修改,那么当前事务可能需要重新尝试或执行冲突处理。
乐观锁的优点是没有显式的锁冲突,对于读多写少的场景可以提高并发性能。但是,如果冲突发生频率较高,可能需要重试或处理冲突的成本会增加。
- 悲观锁:
悲观锁假设多个事务或线程之间会频繁发生冲突,因此在读取数据时就会上锁以防止其他事务修改。常见的实现方式是使用数据库的行级锁或表级锁。当一个事务要读取或修改数据时,它会先申请对应的锁,其他事务再次请求该锁时将被阻塞,直到持有锁的事务释放。
悲观锁的优点是可以确保数据的一致性,避免了数据冲突的可能性。然而,由于加锁会导致其他事务的阻塞,可能会降低并发性能。因此,悲观锁适用于写多读少的场景或对数据一致性要求较高的情况。
需要根据具体的应用场景和并发访问的特点来选择适合的锁策略。在实际应用中,有时也会将乐观锁和悲观锁结合使用,在具体操作前使用乐观锁进行快速检查,若检查失败再回退到悲观锁进行具体的处理。