乐观锁 悲观锁

乐观锁和悲观锁是并发控制的两种策略。悲观锁在操作时假设会有并发问题,通过加锁防止数据冲突;而乐观锁则假设不会有并发问题,在更新时检查是否有其他进程修改数据。Golang中的`sync/atomic`包利用乐观锁实现并发安全,而使用`sync`包则更倾向于悲观锁。乐观锁适用于读多写少的场景,悲观锁适合写多的场景。
摘要由CSDN通过智能技术生成

一、基本概念

乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。

改变一个数值的三个步骤:
①把想修改的数值从某个地方取出来;
②在取出来的数值修改为期望值;
③把修改后的数值保存到原来的地方。

这里面有一个问题,把数值取出来进行修改的时候(做完了①步,正在做②步),如果有另一个过程(进程或线程)对同一个数值进行同样的操作(取值,修改),那么当两个过程都要做③的时候,就肯定有一个过程是白干活的。

  • 悲观锁:悲观锁在操作数据时比较悲观,总认为会发生并发问题。

如果想修改一个数值,立马给这个数值上一把锁,标明这个数值正在被修改,谁也不能修改了;然后才开始三步走,在三步走的过程结束以后,再把锁解除。
当有其他过程想要修改同一个数值时,看到了锁就不进行三步走了,而是选择等待;当锁被解除了,自己在数值也加一把锁,然后开始三步走,在三个步骤走完了,也把锁解除。

上面的过程即是悲观锁,总是存在加锁和解除锁的动作。

  • 乐观锁:乐观锁在操作数据时非常乐观,总认为不会发生并发问题。

如果想修改一个数值,不加锁,正常进行①②步,在进行③的时候,确认一下数值是否进行了修改,如果被修改过,放弃修改,重新走一遍①②③(或者放弃对数值进行修改)。

上面的过程即是乐观锁,不存在加锁和解除锁的动作。

二、实现方式

悲观锁的实现方式是加锁。
乐观锁的实现方式主要有两种:CAS机制和版本号机制。

  • CAS(Compare And Swap)

CAS操作包括了3个操作数:

  • 需要读写的内存位置(V)
  • 进行比较的预期值(A)
  • 拟写入的新值(B)

CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。

这里引出一个新的问题,既然CAS包含了Compare和Swap两个操作,它又如何保证原子性呢?答案是:CAS是由CPU支持的原子操作,其原子性是在硬件层面进行保证的。

CAS的缺点:

  1. ABA问题
    假设有两个线程——线程1和线程2,两个线程按照顺序进行以下操作:
    (1)线程1读取内存中数据为A;
    (2)线程2将该数据修改为B;
    (3)线程2将该数据修改为A;
    (4)线程1对数据进行CAS操作

在第(4)步中,由于内存中数据仍然为A,因此CAS操作成功,但实际上该数据已经被线程2修改过了。这就是ABA问题。

在某些场景下,ABA会带来隐患,例如栈顶问题:一个栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值