IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> CAS原理和源码解析 -> 正文阅读

[人工智能]CAS原理和源码解析


一、CAS是什么?

CAS是Compare And Swap(比较并替换)的缩写。属于硬件同步原语,处理器提供了基本内存操作的原子性保证。CSA操作需要输入两个数值,一个旧值A(期望操作前的值)和一个新值B,在操作期间先对旧值进行比较,若没有发生变化,才交换新值,发生变化则不交换。

二、CAS的原理

1.CAS实现过程

线程会先去比较内存中的值与旧值是否相等,相等则将新值替换原来的旧值,否则自旋。(内存条在硬件方面保证了同一时刻只能有一个线程修改)实际java是通过JVM去调用操作系统,JVM是通过unsafe调用操作系统实现cas操作
在这里插入图片描述

2.Unsafe实现CAS操作

代码示例:


import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class UnsafeDemo {
    volatile int i = 0;
    private static Unsafe unsafe;
    //i字段的偏移量,从逻辑上代表了i字段
    private static long valueOffset;
    static {
        //unsafe = Unsafe.getUnsafe();
        try {
            //通过反射获取unsafe
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
            //获取i字段的offset
            Field iField = CounterUnsafe.class.getDeclaredField("i");
            valueOffset = unsafe.objectFieldOffset(iField);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    public void add() {
        for (;;){
            //获取当前值(this当前对象的引用,valueOffset i的偏移量)
            int current = unsafe.getIntVolatile(this, valueOffset);
            //用CAS将值+1,成功退出自旋,失败则自旋
            if (unsafe.compareAndSwapInt(this, valueOffset, current, current+1))
                break;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        final UnsafeDemo ct = new UnsafeDemo();

        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10000; j++) {
                        ct.add();
                    }
                    System.out.println("done...");
                }
            }).start();
        }

        Thread.sleep(6000L);
        System.out.println(ct.i);
    }
}

AtomicInteger也是通过偏移量来实现CAS操作的(java.util.concurrent.atomic包下面的类基本都是使用的Unsafe来实现CAS)
在这里插入图片描述
在这里插入图片描述

使用例子1:通过AtomicIntegerFieldUpdater实现对User属性的原子更新。
使用场景:已经存在的类,没有使用AtomicInteger来修饰属性(id,age),需要修改属性,就需要用
AtomicIntegerFieldUpdater来实现对属性进行CAS更新。注意:属性必须用volatile修饰,否则AtomicIntegerFieldUpdater没办法使用
在这里插入图片描述
输出结果:在这里插入图片描述
使用例子2:这会出现原子性问题(多个线程获取都为null,然后都对owner修改),AtomicReference实现引用类型的更新,修改对象的引用。
在这里插入图片描述
使用后:
在这里插入图片描述

三、CAS的ABA问题

1、ABA问题解释:线程1、线程2同时读取i=0;线程1、线程2都要执行CAS操作,如果线程2操作完成在线程1之后,那么线程1执行完成之后,线程1再执行CAS(0,1),将i的值改为0;

在这里插入图片描述
最后的结果是线程1、线程2都执行成功(如果线程1执行完之后没有执行CAS(0,1),那么线程2执行CAS(0,1)会失败)。
问题原因:后面的1已经不是原来的1了
示例2:
在这里插入图片描述

在这里插入图片描述
解决ABA问题方法:加入版本号
存在ABA问题的代码示范:


import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

// 实现一个 栈(后进先出)
public class Stack {
    // top cas无锁修改
    AtomicReference<Node> top = new AtomicReference<Node>();

    public void push(Node node) { // 入栈
        Node oldTop;
        do {
            oldTop = top.get();
            node.next = oldTop;
        }
        while (!top.compareAndSet(oldTop, node)); // CAS 替换栈顶
    }


    // 出栈 -- 取出栈顶 ,为了演示ABA效果, 增加一个CAS操作的延时
    public Node pop(int time) {

        Node newTop;
        Node oldTop;
        do {
            oldTop = top.get();
            if (oldTop == null) {   //如果没有值,就返回null
                return null;
            }
            newTop = oldTop.next;
            if (time != 0) {    //模拟延时
                LockSupport.parkNanos(1000 * 1000 * time); // 休眠指定的时间
            }
        }
        while (!top.compareAndSet(oldTop, newTop));     //将下一个节点设置为top
        return oldTop;      //将旧的Top作为值返回
    }
}

使用添加版本号的代码示例:


import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.LockSupport;

public class ConcurrentStack {
    // top cas无锁修改
    //AtomicReference<Node> top = new AtomicReference<Node>();
    AtomicStampedReference<Node> top =
            new AtomicStampedReference<>(null, 0);

    public void push(Node node) { // 入栈
        Node oldTop;
        int v;
        do {
            v = top.getStamp();
            oldTop = top.getReference();
            node.next = oldTop;
        }
        while (!top.compareAndSet(oldTop, node, v, v+1)); // CAS 替换栈顶
    }


    // 出栈 -- 取出栈顶 ,为了演示ABA效果, 增加一个CAS操作的延时
    public Node pop(int time) {

        Node newTop;
        Node oldTop;
        int v;

        do {
            v = top.getStamp();
            oldTop = top.getReference();
            if (oldTop == null) {   //如果没有值,就返回null
                return null;
            }
            newTop = oldTop.next;
            if (time != 0) {    //模拟延时
                LockSupport.parkNanos(1000 * 1000 * time); // 休眠指定的时间
            }
        }
        while (!top.compareAndSet(oldTop, newTop, v, v+1));     //将下一个节点设置为top
        return oldTop;      //将旧的Top作为值返回
    }
}

AtomicStampedReference此类带有版本号,替换原有的 AtomicReference,这样解决了ABA问题

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:36:04  更:2021-08-12 16:36:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 20:23:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码