乐观锁与悲观锁的总结

乐观锁

定义

在操作时持乐观态度,认为操作时其它线程不会修改数据,因此不会锁定数据,但是在更新数据时会用版本号或者CAS算法判断数据在本次操作过程中是否被更改,如果被更改,则修改失败。

所以乐观锁虽然名字带锁,但是实际上并不会对数据进行锁定操作,其它线程仍然可以自由地读写数据,不会造成死锁等问题。

适用场景

乐观锁不会锁定数据,所以其它需要读取数据的线程不需要等待,但是如果更新频繁,频繁地出现修改失败回滚的情况,反而会导致性能及使用体验的问题。

因此乐观锁适用于需要频繁读取数据,但是较少更新数据的场景。

实际应用

Java中原子变量使用了CAS算法来避免加锁,同时保证数据修改的正确性:

  1. 使用volatile声明该变量为线程间共享变量;

  2. 使用CAS算法保证变量修改的正确性,我们可以调用compareAndSet函数来尝试修改原子变量,该函数会返回修改的结果,如果成功,则操作完成,如果失败则获取新值处理后继续尝试;

实现方式

乐观锁通常有两种实现方式:

  1. 通过版本号机制实现;
  2. 通过CAS(compare and swap)算法实现;

版本号机制实现

  1. 取出数据时同时获取数据当前的version;
  2. 更新数据时也带上这个version;
  3. 服务端比对请求的version与目前数据的version是否一致;
  4. 如果一致,则更新数据,如果不一致,则修改失败;

CAS算法实现

CAS算法简介

CAS是compare and swap的缩写,算法逻辑就是当一个线程要修改某个数据时,需要携带上之前的原数据,服务端会将这个原数据与当前数据进行比对,如果一致,则将当前数据替换为申请修改的数据,如果不一致,则修改失败。

ABA问题
  • 线程T1与T2均取出A数据;
  • T1要将A数据更新为B,而此时T2速度更快,将数据从A更新为了C,然后又将C更新为了A;
  • T1的更新请求到达服务端,服务端比对T1携带的原数据A与当前数据A,结果相等,于是将数据更新为了B,但实际数据已经几经变化了;

在大多数情况下,这都是没有问题的,但如果我们需要严格保证原数据未经变动时,则可能出现问题,相比较使用版本号实现的乐观锁则可以避免此问题。

悲观锁

定义

在操作时持悲观态度,认为其它线程会修改数据,所以更新数据时对数据进行锁定,加锁后,同一时间只能有一个线程执行,其它线程只能等待直到锁被其它线程释放。

适用场景

悲观锁可以保证数据操作时的正确性,不会出现数据因被其它线程修改而失败的情况,但是它会限制其它线程读取数据。

所以悲观锁更适用于修改频繁,使用乐观锁会频繁冲突回滚,但读取较少的场景。

实际应用

Java的synchronized关键字就是一种悲观锁

参考文章

乐观锁、悲观锁,这一篇就够了!

原子操作CAS及其实现类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值