面试必备之 悲观锁与乐观锁


悲观锁与乐观锁并不是真正意义上的锁,而是对数据的加锁策略

悲观锁(Pessimistic Lock)

是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。

优缺点与适用场景

优点:对每次读取数据都进行加锁,解决了脏读、幻读和不可重复读等可能存在的问题
缺点:每次都加锁降低了系统的吞吐量,并发量大时许多线程都被阻塞
适用场景:适用于读少写多的情况下,经常产生冲突的场景

实现方式(mysql里)

select for .... update
获取锁的前提:结果集中的数据没有使用排他锁或共享锁时,才能获取锁,否则将会阻塞。

例如、

select * from tbl_user where id=1 for update;

需要注意的是,for update 生效需要同时满足两个条件时才生效:

  1. 数据库的引擎为 innoDB
  2. 操作位于事务块中(BEGIN/COMMIT)

当执行 select … for update时,将会把数据锁住,因此,我们需要注意一下锁的级别。MySQL InnoDB 默认为行级锁。当查询语句指定了主键时,MySQL会执行「行级锁」,否则MySQL会执行「表锁」。
常见情况如下:

  • 若明确指明主键,且结果集有数据,行锁;
  • 若明确指明主键,结果集无数据,则无锁;
  • 若无主键,且非主键字段无索引,则表锁;
  • 若使用主键但主键不明确,则使用表锁;

实例
在窗口1上执行

// 关闭mysql数据库的自动提交属性
set autocommit=0;
// 开启事务
BEGIN;
SELECT * FROM tbl_user where id=1 for update;

然后再在窗口2执行获取锁语句 select * from tbl_user where id=1 for update;

那么窗口2并没有像窗口1一样,立刻返回结果,而是发生了阻塞,返回了一个error信息

ERROR 1205: Lock wait timeout exceeded; try restarting transaction

乐观锁(Optimistic Locking)

乐观锁是相对悲观锁而言的,是一种对数据的修改持有悲观态度的并发控制方式。乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。

优缺点与适用场景

优点:省去了锁的开销,加大了系统的整个吞吐量
缺点:1、ABA问题。 2、循环时间长开销大。 3、只能保证一个共享变量的原子操作

  • ABA 问题

线程1从数据库中取出某数据为A,这时候线程2也从数据库中某数据为A;
并且线程2进行了一些操作将数据变成了 B、然后线程2又将数据变成 A,
这时候线程1进行 CAS 操作发现数据库中仍然是A,然后线程一操作成功。
尽管线程一的 CAS 操作成功,但是不代表这个过程就是没有问题的。

  • 循环时间长开销大

自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。

  • 只能保证一个共享变量的原子操作

CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。

适用场景:适用于读多写少的情况(多读场景),冲突较少的场景

实现方式

1、版本号机制

在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加1。
当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

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

CAS算法涉及到三个操作数
1、需要读写的内存值 V
2、进行比较的值 A
3、拟写入的新值 B

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值