CAS相关知识

27 篇文章 0 订阅

乐观锁和悲观锁是两种思想,他们的应用相当广泛,不局限于某种语言。

悲观锁认为所有情况都是悲观的,悲观锁的实现方法是加锁,java中常用synchronized关键字对代码块加锁,mysql中通过排他锁对数据加锁。

乐观锁认为每次不加锁,假设每次修改数据之前其他线程一定不会修改,如果因为修改产生冲突就重试,知道成功为止,常见的实现方式有CAS机制。(可以理解为无堵塞多线程争抢资源)。

CAS机制(compare and swap,比较并交换):是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性产生的数据不一致问题。

两者的比较:

public class castest11 {
    static int i=0;

    public static void increment(){
        i++;
    }
}

我们建立一个类,用1000个线程去调用它,对 i 进行自增操作,因为i++不是原子操作,整个线程不安全,其结果很难到达1000。
解决的方法很简单,对方法加锁,如:

public class CAStest11 {
    static int i=0;

    public synchronized static void increment(){
        i++;
    }
}

在加锁操作之后,最多只能有一个线程进入这个方法,保证了线程的安全性。然而,一个简单的自增操作就用了synchronized关键字,难免有些大材小用,会很影响我们的速度。

现在我们需要用一种方法代替synchronized的加锁,还要保证线程安全。
例如:
class CAStest12{
    do{
     
        int k= i;
        int j=k + i;
    }while(compareAndSet(i,k,j))
}
你会发现,这样的线程时安全的,对于compareAndSet操作,这是对应于操作系统的一条硬件操作指令,

 

优缺点和使用场景:(CAS的ABA问题)
  ABA问题:当线程A即将进行第三步时,线程B将i的值+1,之后又-1,然后线程A执行第三步,这时候线程A认为并没有改过i的值,因为i的值没有改变。
  对于基本类型的值来说,这种数字的改变没有太大的影响,但是如果是引用类型的话,会造成很大的影响。
  


  优化:由于采用CAS的操作是没法进行加锁的,所以,所有的线程都可以进入increment方法。
            假设进入的线程太多,就会出现一个问题:由于线程太密集,太多人想修改i的值,然而大部分人修改不成功,白白循环浪费资源。
            因此,Java8中引入了一个cell[]数组,我们假设有100个线程要对i进行自增操作,这时候,冲突会大大增加,系统会将100个线程分配到不同的cell数组中。
           (例如。我们假设cell[10]有10个元素,系统会将100个线程分成10组,每一组对cell数组自增,然后对10个数组进行汇总,进而得到100,这样就等价于对100个线程进行汇总,)


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值