博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
乐观锁与悲观锁的总结
阅读量:2058 次
发布时间:2019-04-29

本文共 1126 字,大约阅读时间需要 3 分钟。

乐观锁

定义

在操作时持乐观态度,认为操作时其它线程不会修改数据,因此不会锁定数据,但是在更新数据时会用版本号或者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关键字就是一种悲观锁

参考文章

《》

《》

转载地址:http://rptlf.baihongyu.com/

你可能感兴趣的文章
[译]数据包在 Kubernetes 中的一生(2)
查看>>
[译]数据包在 Kubernetes 中的一生(3)
查看>>
从源头解决 Service Mesh 问题最彻底!
查看>>
一次“不负责任”的 K8s 网络故障排查经验分享
查看>>
一次有趣的 Docker 网络问题排查经历
查看>>
KubeSphere Meetup 北京站火热报名中 | 搭载 CIC 2021 云计算峰会
查看>>
深入理解 Linux Cgroup 系列(一):基本概念
查看>>
深入理解 Linux Cgroup 系列(二):玩转 CPU
查看>>
云原生周报第 1 期 | 2019-06-24~2019-06-28
查看>>
Kubernetes Pod 驱逐详解
查看>>
kubectl 创建 Pod 背后到底发生了什么?
查看>>
[译] Kubernetes 儿童插图指南
查看>>
云原生周报第 2 期 | 2019-07-01~2019-07-05
查看>>
kubectl 创建 Pod 背后到底发生了什么?
查看>>
Kube-scheduler 源码分析(二):调度程序启动前逻辑
查看>>
kubernetes 1.15 有哪些让人眼前一亮的新特性?
查看>>
云原生周报:第 3 期
查看>>
深入理解 Linux Cgroup 系列(三):内存
查看>>
7月最新Java微服务资料
查看>>
Linux 指令
查看>>