展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > CAS与Java中的乐观锁的应用方法

CAS与Java中的乐观锁的应用方法

什么是CASCAS是CompareAndSwap,即比较和交换。为什么CAS没有用到锁还能保证并发情况下安全的操作数据呢,名字其实非常直观的表明了CAS的原理,具体修改数据过程如下:用CAS操作数据时,将数据原始值和要修改的值一并传递给方法比较当前目标变量值与传进去的原始值是否相同如果相同,表示目标变量没有被其他线程修改,直接修改目标变量值即可如果目标变量值与原始值不同,那么证明目标变量已经被其他线程修改过,本次CAS修改失败从上述过程可以看到CAS其实保证的是安全的修改数据,但是修改存在失败的可能性,即

本文目录

    什么是CAS

    CAS是CompareAndSwap,即比较和交换。为什么CAS没有用到锁还能保证并发情况下安全的操作数据呢,名字其实非常直观的表明了CAS的原理,具体修改数据过程如下:

    1. 用CAS操作数据时,将数据原始值和要修改的值一并传递给方法

    2. 比较当前目标变量值与传进去的原始值是否相同

    3. 如果相同,表示目标变量没有被其他线程修改,直接修改目标变量值即可

    4. 如果目标变量值与原始值不同,那么证明目标变量已经被其他线程修改过,本次CAS修改失败

    从上述过程可以看到CAS其实保证的是安全的修改数据,但是修改存在失败的可能性,即目标变量数据修改不成功,这个时候我们要循环判断CAS修改数据结果,如果失败进行重试。

    思维比较缜密的同学可能担心CAS本身这个比较与替换的操作产生并发安全问题,实际应用中这种情况不会发生,比较与替换由JDK借助硬件级别的CAS原语来保证比较替换是一个原子性动作。

    CAS实现无锁编程

    无锁编程指的是在不使用锁的情况下保证安全的操作共享变量在并发编程中,我们用各种锁来保证共享变量的安全性。即在保证一个线程未操作完共享变量的时候其他线程不能操作同一共享变量。
    正确的使用锁可以保证并发情况下数据安全,但是在并发程度不高,竞争不激烈的时候,获取锁和释放锁就成了没必要的性能浪费。这种情况下可以可考虑利用CAS保证数据安全,实现无锁编程 

    头疼的ABA问题

    上面我们已经了解了CAS保证安全操作共享变量的原理,但是上述CAS操作还存在缺陷。假设当前线程访问的共享变量值为A,在线程1访问共享变量过程中,线程2操作共享变量将其赋值为B,线程2处理完自己的逻辑后又将共享变量赋值为A。这时线程1比较共享变量值A与原始值A相同,误以为没有其他线程操作共享变量,直接返回操作成功。这就是ABA问题。虽然大部分业务不需要关心共享变量是否有过其他更改,只要原始值与当前值一致就能得到正确的结果,但是有一些敏感场景不光要考虑共享变量结果上等同于没有被修改过,同时也不能接受共享变量过程上被其他线程修改过。幸运的是ABA问题也有成熟的解决方案,我们为共享变量添加一个版本号,每当共享变量被修改这个版本号值就会自增。在CAS操作中我们比较的不是原始变量值,而是共享变量的版本号。每次操作共享变量更新的版本号都是唯一的,所以能够避免ABA问题。 

    具体应用场景 

    JDK中的CAS应用

    首先多个线程对普通变量进行并发操作是不安全的,一个线程的操作结果可能被其他线程覆盖掉,比如现在我们用两个线程,每个线程将初始值为1的共享变量增加一,如果没有同步机制的话共享变量结果很可能小于3。即可能线程1和线程2都读到了初始值1,线程1将其赋值为2,线程2所在内存读取到的值还是1不会变,线程2也将变量增加1然后赋值成2,这样最终结果是2小于预期结果3。自增操作不是原子性操作导致了这个共享变量操作不安全问题。为了解决这个问题,JDK提供了一系列原子类提供相应的原子操作。下面是AtomicInteger中的getAndIncrement方法源码,让我们从源码来看是怎么利用CAS实现线程安全的原子性的整形变量相加操作。

    /**
    * 原子性的将当前值增加1
    *
    * @return 返回自增前的值
    */
    public final int getAndIncrement() {
       return unsafe.getAndAddInt(this, valueOffset, 1);
    }
     

    可以看到getAndIncrement实际调用了UnSafe类的getAndAddInt方法实现原子操作,下面是getAndAddInt源代码

    /**
    * 原子的将给定值与目标字变量相加并重新赋值给目标变量
    *
    * @param o 要更新的变量所在的对象
    * @param offset 变量字段的内存偏移值
    * @param delta 要增加的数字值
    * @return 更改前的原始值
    * @since 1.8
    */
    public final int getAndAddInt(Object o, long offset, int delta) {
       int v;
       do {
        // 获取当前目标目标变量值
           v = getIntVolatile(o, offset);
       // 这句代码是关键, 自旋保证相加操作一定成功
       // 如果不成功继续运行上一句代码, 获取被其他
       // 线程抢先修改的变量值, 在新值基础上尝试相加
       // 操作, 保证了相加操作的原子性
       } while (!compareAndSwapInt(o, offset, v, v + delta));
       return v;
    }
     

    我们都对锁很熟悉, 比如可重入锁ReentrantLock, JDK提供的各种锁基本都依赖AbstractQueuedSynchronizer这个类, 当多个线程尝试获取锁时会进入一个队列等待, 其中多线程入队操作的原子性就是用CAS来保证的. 源代码如下:

    /**
    * 锁底层等待获取锁的线程入队操作
    * @param node 要入队的线程节点
    * @return 入队节点的前驱节点
    */
    private Node enq(final Node node) {
    // 自旋等待节点入队, 通过cas保证并发情况下node安全正确入队
       for (;;) {
           Node t = tail;
           // head为空时构造dummy node初始化head和tail
           if (t == null) {
               if (compareAndSetHead(new Node()))
                   tail = head;
           } else {
               node.prev = t;
               // 如果cas设置tail失败了
               // 下个循环取到了最新的其他线程抢先设置的tail
               // 继续尝试设置.
               if (compareAndSetTail(t, node)) {
                   t.next = node;
                   return t;
               }
           }
       }
    }
    /**
    * 原子性的设置tail尾节点为新入队的节点
    */
    private final boolean compareAndSetTail(Node expect, Node update) {
    // 可以看到此处又是调用了Unsafe类下的原子操作方法
    // 如果目标字段(tail尾节点字段)当前值是预期值
    // 即没有被其他线程抢先修改成功, 那么就设置成功
    // 返回true
       return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
       

    企业开发中的乐观锁应用

    除了JDK中Uusafe类提供的各种原子性操作外,我们实际开发中可以用CAS思想保证并发情况下安全的操作数据库。假设有user表结构以及数据如下, version字段是实现乐观锁的关键

    idusercoupon_numversion
    1朱小明00

    假设我们有一个用户领取优惠券的按钮,怎么防止用户快速点击按钮造成重复领取优惠券的情况呢。我们要安全的更改id为1的用户的coupon_num优惠券数量,将version字段作为CAS比较的版本号,即可避免重复增加优惠券数量,比较和替换这个逻辑通过WHERE条件来实现. 涉及sql如下:

    UPDATE user 
    SET coupon_num = coupon_num + 1, version = version + 1
    WHERE version = 0

    可以看到,我们查询出id为1的数据, 版本号为0,修改数据的同时把当前版本号当做条件即可实现安全修改,如果修改失败,证明已经被其他线程修改过,然后看具体业务决定是否需要自旋尝试再次修改。这里要注意考虑竞争激烈的情况下多个线程自旋导致过度的性能消耗,根据并发量选择适合自己业务的方式

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。