Java多线程~CAS的原理及其应用

目录

什么是CAS

CAS的实现原理

CAS的ABA问题

什么是ABA问题 

解决方案


什么是CAS

CAS(Compare And Swap):比较并交换,CAS是乐观锁的一种实现

一个CAS涉及到的操作

假设内存中的原数据V,旧的预期值A,要修改的的值B

1.比较V与A的值是否相等(Compare)

2.如果比较相等,则将B写入V(Swap)

3.返回操作是否成功

简单的说,CAS就是直接尝试修改变量,再返回修改的结果.比较读和写两个时间点主存中变量的值是否相等,如果相等就把要修改的值写回主存中,如果不相等就不做任何操作,修改成功返回true,修改失败就返回false 

CAS的实现原理

Java中的CAS是基于Unsafe这个类提供的CAS操作 ,Unsafe中的CAS又是基于操作系统和CPU提供的机制来实现的,即硬件予以支持,软件层面才能做到

CAS的ABA问题

什么是ABA问题 

假设有两个线程,t1和t2,有一个共享变量num,初始值为A,t1线程想要使用CAS将A修改为Z,此时t1需要进行如下操作:先从主存中读取num的值并记录下来,之后使用CAS判定当前num的值是否为A,如果为A就修改为Z。但是在这个过程中可能t2线程先将num的值修改为B,又将num的值从B修改回A,这就是CAS的ABA问题

代码示例(模拟CAS的ABA问题)

利用sleep方法来简单模拟ABA问题:

1、t1线程想要修改num的为5,首先t1线程从主存中读取num的值并记录为旧的预期值,此时旧的预期值为2

2、在t1线程开始修改操作之前,t2线程先将主存中的num改为15,再将num从15改回2,此时线程2执行结束退出

3、t1线程继续执行修改操作,从主存中读取到当前num值为2,与预期值相等,就进行修改操作. 

package threadhomework;

/**
 * Created with IntelliJ IDEA.
 * Description: ABA问题示例
 * User: Li_yizYa
 * Date: 2022—09—24
 * Time: 13:23
 */
public class CASDemo {
    private static int num = 2;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int oldNum = num;//旧的预期值
                    //利用sleep方法模拟t2在t1获取到共享变量后完成两次修改操作
                    Thread.sleep(200);
                    //如果旧的预期值与当前num的值相等则修改
                    if(oldNum == num) {
                        num = 5;
                        System.out.println("t1线程修改成功,修改后num的值为: " + num);
                    } else {
                        System.out.println("t1线程修改失败");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                num = 15;
                System.out.println("t2线程第一次修改num,修改为: " + num);
                num = 2;
                System.out.println("t2线程第二次修改num,修改为: " + num);
            }
        });
        t1.start();
        //保证t1线程先执行
        Thread.sleep(100);
        t2.start();
    }
}

 

解决方案

给要修改的值引入版本号,在CAS比较数据当前值和旧值的同时,也要比较版本号是否符合预期.

如果旧值与当前值相同,则开始比较版本号:

· 如果当前版本号与旧的预期版本号相同,则进行修改,版本号+1

· 如果当前版本号与旧的预期版本号不相同,则修改失败.

在Java标准库中提供了AtomicStampedReference<E>类,这个类可以对某个类进行包装,在内部就提供了版本管理的功能.

例如上述ABA问题演示代码,再加上一个版本号就可以解决ABA问题

package threadhomework;

/**
 * Created with IntelliJ IDEA.
 * Description: ABA问题示例
 * User: Li_yizYa
 * Date: 2022—09—24
 * Time: 13:23
 */
public class CASDemo {
    private static int num = 2;
    private static int version = 1;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int oldNum = num;
                    int oldVersion = version;
                    Thread.sleep(200);
                    if(oldNum == num && oldVersion == version) {
                        num = 5;
                        //修改成功,版本号+1
                        version++;
                        System.out.println("t1线程修改成功,修改后num的值为: " + num + " 当前版本号为: " + version);
                    } else {
                        System.out.println("t1线程修改失败,版本号不匹配 旧的预期版本号为: " + oldVersion + " 当前版本号为: " + version);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                num = 15;
                version++;//修改成功,版本号+1
                System.out.println("t2线程第一次修改num,修改为: " + num + " 当前版本号为: " + version);
                num = 2;
                version++;//修改成功,版本号+1
                System.out.println("t2线程第二次修改num,修改为: " + num + " 当前版本号为: " + version);
            }
        });
        t1.start();
        Thread.sleep(100);
        t2.start();
    }
}

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Li_yizYa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值