Java乐观锁的实现原理

什么是乐观锁?

在并发编程中,多个线程同时对同一资源进行操作时,需要使用锁来保证数据的一致性。
乐观锁与悲观锁是两种不同的锁机制。
悲观锁会在整个操作期间占用资源的独占性,以保证数据的一致性,而乐观锁则是基于版本号或时间戳的机制,在操作前做一个乐观的估计,如果操作成功,则版本号加1,如果失败,则重试。因为乐观锁不需要在整个操作期间占用资源的独占性,所以可以提高并发性。

Java中乐观锁的实现方式

Java中的乐观锁主要有两种实现方式:CAS(Compare and Swap)和版本号控制。

CAS

CAS是实现乐观锁的核心算法,它通过比较内存中的值是否和预期的值相等来判断是否存在冲突。如果存在,则返回失败;如果不存在,则执行更新操作。

CAS 它包含了 3 个参数:V(需要更新的变量)、E(预期值)和 N(最新值)。只有当需要更新的变量等于预期值时,需要更新的变量才会被设置为最新值,如果更新值和预期值不同,则说明已经有其它线程更新了需要更新的变量,此时当前线程不做操作,返回 V 的真实值。

Java中提供了AtomicInteger、AtomicLong、AtomicReference等原子类来支持CAS操作。

下面是一个简单的CAS示例:

代码

public class Counter {private AtomicInteger value = new AtomicInteger(0);public void increment() {int expect;int update;do {expect = value.get();update = expect + 1;} while (!value.compareAndSet(expect, update));}
}

在这个示例中,increment()方法会不断地执行CAS操作,直到更新成功为止。

版本号控制

版本号控制是乐观锁的另一种实现方式。

每当一个线程要修改数据时,都会先读取当前的版本号或时间戳,并将其保存下来。线程完成修改后,会再次读取当前的版本号或时间戳,如果发现已经变化,则说明有其他线程对数据进行了修改,此时需要回滚并重试。

下面是一个简单的版本号控制示例:

代码

public class Counter {private int value = 0;private int version = 0;public void increment() {int currentVersion;int currentValue;do {currentVersion = version;currentValue = value;currentValue++;} while (currentVersion != version);value = currentValue;version = currentVersion + 1;}
}

在这个示例中,increment()方法会不断地执行循环,直到当前的版本号与保存的版本号相同为止。如果版本号不同,则说明有其他线程修改了数据,此时需要回滚并重试。

Java中乐观锁的案例

ConcurrentHashMap

ConcurrentHashMap是Java中的一个线程安全的哈希表实现,它使用分离锁(Segment)来保证线程安全。每个Segment都是一个独立的哈希表,每个操作只锁定相关的Segment,因此可以支持更高的并发性。

ConcurrentHashMap使用了一种基于CAS的技术来实现乐观锁,它通过比较当前的value和预期的value是否相等来判断是否存在冲突。如果存在,则返回失败;如果不存在,则执行更新操作。

LongAdder

在 JDK1.8 中,Java 提供了一个新的原子类 LongAdder。LongAdder 在高并发场景下会比 AtomicInteger 和 AtomicLong 的性能更好,代价就是会消耗更多的内存空间。

LongAdder 的原理就是降低操作共享变量的并发数,也就是将对单一共享变量的操作压力分散到多个变量值上,将竞争的每个写线程的 value 值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的 value 值进行 CAS 操作,最后在读取值的时候会将原子操作的共享变量与各个分散在数组的 value 值相加,返回一个近似准确的数值。

数据库并发控制

在日常开发中,使用乐观锁最常见的场景就是数据库的更新操作了。

为了保证操作数据库的原子性,我们常常会为每一条数据定义一个版本号,并在更新前获取到它,到了更新数据库的时候,还要判断下已经获取的版本号是否被更新过,如果没有,则执行该操作。

总结

在Java中,并发编程的时候可以使用Synchronized 和 Lock 实现的同步锁机制,但是两种同步锁都属于悲观锁。

悲观锁在高并发的场景下,激烈的锁竞争会造成线程阻塞,大量阻塞线程会导致系统的上下文切换,增加系统的性能开销,这个时候乐观锁就是我们可以考虑的一种方案。

当然CAS 乐观锁在平常使用时比较受限,它只能保证单个变量操作的原子性,当涉及到多个变量时,CAS 就无能为力了。

好了,以上就是今天分享的全部内容,enjoy~ 欢迎关注我的微信公众号【AI黑板报】

本文由博客一文多发平台 OpenWrite 发布!

Java乐观锁的实现原理和典型案例相关推荐

  1. Java乐观锁的实现原理(案例)

    锁,当多个事务同时对数据库表中的同一条数据操作时,如果没有加锁机制的话,就会产生脏数据(duty data). 有2种机制可以解决这个问题:就是悲观锁和乐观锁了. 这里我们使用乐观锁,通过案例代码来实 ...

  2. java乐观锁实现_Java 乐观锁原理与实战演练

    原标题:Java 乐观锁原理与实战演练 一. 前言 最近在做一个简单审批流程的项目,由于只有固定二级审批所以没有工作流组件,然后就遇到一个审批节点捞单时候,多个人同时审批时候如何保证业务正常运行的问题 ...

  3. Java 乐观锁和悲观锁

    文章目录 Java 乐观锁和悲观锁 1.悲观锁 2.乐观锁 2.1 CAS 2.2 模拟CAS算法 2.3 JUC 2.4 CAS中的ABA问题 2.5 使用CAS会引发的问题 Java 乐观锁和悲观 ...

  4. java 乐观锁 实例_JAVA乐观锁实现-CAS(示例代码)

    是什么 全称compare and swap,一个CPU原子指令,在硬件层面实现的机制,体现了乐观锁的思想. JVM用C语言封装了汇编调用.Java的基础库中有很多类就是基于JNI调用C接口实现了多线 ...

  5. 【mysql】悲观锁和乐观锁的实现原理

    java多线程中的锁分类多种多样,其中有一种主要的分类方式就是乐观和悲观进行划分的. 一.乐观锁概念 说是写乐观锁的概念,但是通常乐观锁和悲观锁的概念都要一块写.对比着来才更有意义. 1.悲观锁概念 ...

  6. Java 乐观锁 悲观锁

    一.乐观锁.悲观锁定义 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据.因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行 ...

  7. java 乐观锁和悲观锁,Threadlocal

    7.乐观锁和悲观锁 悲观锁(Pessimistic Lock)顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到 ...

  8. 乐观锁-基于CAS原理

    乐观锁理论基础 乐观锁的操作过程中其实没有没有任何锁的参与,乐观锁只是和悲观锁相对,严格的说乐观锁不能称之为锁.下面我们就通过乐观锁与悲观锁的对比来更好的理解乐观锁. 乐观锁与悲观锁的概念 乐观锁:总 ...

  9. Java乐观锁%悲观锁

    1.乐观锁 尝试去获得一把锁,无论获得还是无法获得立刻返回True/False 不会阻塞进程,使用此锁可在获取锁的过程中完成其它操作.如下例子演示了在线程1获得了锁之后,线程2使用trylock()可 ...

最新文章

  1. 计算程序运行时间(time_t, clock_t)
  2. 《统计学习方法》-李航、《机器学习-西瓜书》-周志华总结+Python代码连载(一)--模型选择+误差评估
  3. java学习一 path与classpath
  4. HTML5中的websocket图片直播
  5. 【错误记录】Android Studio 中查看 Gradle 配置的方法源码 ( 配置 gradle-wrapper.properties 中版本为 gradle-x.x.x-all.zip )
  6. .NET Core微服务之路:基于Ocelot的API网关实现--http/https协议篇
  7. javascript实现定时器四秒后跳转到秋秋淘衣坊首页(setInterval计时器)
  8. input Type
  9. eos节点服务器_EOS跌落神坛?
  10. 19.UNIX 环境高级编程--伪终端
  11. pip下载opencv报错
  12. 金税开票软件,开票时弹出FRM-000013
  13. 夜场票为何一票难求?故宫院长在彩排现场解答观众
  14. OpenCV求(图像)矩阵中最大值,最小值函数minMaxLoc() vs minMaxIdx()
  15. 因为你是我的英雄音译_我可以成为你的英雄宝贝
  16. LTE IPV6地址配置
  17. 如何解决Error while saving file: Unable to open database file问题
  18. 国家计算机职业技能鉴定4级考试内容大全
  19. 2D中小游戏开发C++游戏教程
  20. java开发系统内核:让内核从严重错误中恢复

热门文章

  1. 十三、熵编码CAVLC:1、编码原理
  2. Android快速入门
  3. 记一次golang/json转义问题
  4. EasyPoi实现Excel数据导入
  5. Fragment的用法,举例介绍
  6. 爬取小说正文存为txt
  7. 欧式距离、标准化欧式距离、马氏距离、余弦距离
  8. 解决新版树莓派无法开启CSI接口摄像头问题
  9. Java中main方法的6种声明形式
  10. win7如何连接域控服务器,win7系统创建域控制器的操作方法