MySQL锁(4):乐观锁与悲观锁

乐观锁

1)乐观锁特点

乐观锁( Optimistic Locking ) 假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测。如果发现冲突了,则返回错误的信息,让用户决定如何去做。

2)乐观锁实现

实现乐观锁一般有以下2种方式,

版本号机制

一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数。这个字段在Java中一般使用atomic中的整数类型实现。

当数据被修改时,version值会加1。当事务A要更新数据值时,在读取数据的同时也会读取version值。事务A处理对事务处理完成后,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

整个过程可以使用下图表示为,
image

CAS算法

compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

  1. 需要读写的内存值 V
  2. 进行比较的值 A
  3. 拟写入的新值 B

当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试

3)乐观锁缺点

  1. ABA问题
    这是CAS算法常见的问题。
    如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那就能说明它的值没有被其他线程修改过了吗?
    很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。
  2. 自旋时间长开销大
    自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。
  3. 只能保证一个共享变量的原子操作
    CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。

悲观锁

悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作

这点跟Java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,直接调用数据库的相关语句就可以。

说到这里,由悲观锁涉及到的另外两个锁概念就出来了,它们就是共享锁与排它锁。共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴

乐观锁与悲观锁使用场景

悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法。

悲观锁和乐观锁大部分场景下差异不大,一些独特场景下有一些差别,一般可以从如下几个方面来判断:

  1. 响应速度:如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁
  2. 高并发:如果并发率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大
  3. 重试代价:如果重试代价大,建议采用悲观锁
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值