CAS自旋锁实现思想

什么是CAS

  • 比较并交换
// 两个参数分别是:期望值与更新后的值,方法返回值为布尔类型,如果返回true,则进行交换
public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
  • Unsafe:rt.jar包下的jvm原生类
 public final int getAndIncrement() {
		 // this代表当前对象 , valueOffset代表内存偏移量,偏移量可以简单理解为地址的意思
        return unsafe.getAndAddInt(this, valueOffset, 1); // this代表当前对象 , valueOffset
    }

  • CAS底层通过系统原语来执行的,原语的执行不允许被打断,从而保证了并发下的原子性

  • public final int getAndAddInt(Object var1, long var2, int var4) {
            int var5;
            do {
                //获取当前对象与内存地址
                var5 = this.getIntVolatile(var1, var2);
                //修改成功跳出循环,var1代表当前对象,var2代表偏移量,当再一次传入对象和地址时会上上一次传入的进行比较,如果相等,那么就进行修改,取反表示修改成功跳出循环
            } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    
            return var5;
        }
    
    • 如果主物理内存和线程工作空间的期望值不一样就会一直while循环

    • Unsafe+CAS(思想)=自旋

CAS缺点

  1. 循环时间长,开销时间大(自旋),cpu使用升高

  2. 只能保证一个共享变量的原子性操作,只能保证一个对象,而加锁可以保证多段

  3. ABA问题:线程时间间隔,导致收尾结果一致,中间发生多次交换

    1. 原子引用更新:解决ABA问题

    2. 怎么解决ABA问题呢?

      • 就是加入时间戳,也就是版本号

      • 带时间戳的原子引用类

package TestDome;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class ABADome {
    // 这里要传一个初始值
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        System.out.println("===========以下是ABA问题的产生==============");
        new Thread(()->{
            // 期望值是100就修改为101;
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"T1").start();

        new Thread(()->{
            // 线程睡眠一秒,保证T1线程完成一次ABA操作
            try {
                TimeUnit.SECONDS.sleep(1);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            // 期望值是100就修改为101;
            System.out.println(atomicReference.compareAndSet(100, 2019)+"\t"+atomicReference.get());

        },"T2").start();
        // 睡眠两秒钟,保证上面的ABA彻底完成
        try { TimeUnit.SECONDS.sleep(2); }catch (InterruptedException e){ e.printStackTrace(); }
        System.out.println("===========以下是ABA问题的解决==============");

        new Thread(()->{
            int stampe = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t的第一次版本号: "+stampe);
            try { TimeUnit.SECONDS.sleep(1); }catch (InterruptedException e){ e.printStackTrace(); }
            atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t的第二次版本号: "+atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t的第三次版本号: "+atomicStampedReference.getStamp());
            },"T3").start();

        new Thread(()->{
            int stampe = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t的第一次版本号: "+stampe);
            try { TimeUnit.SECONDS.sleep(3); }catch (InterruptedException e){ e.printStackTrace(); }
            boolean result = atomicStampedReference.compareAndSet(100,2019,stampe,stampe+1);
            System.out.println(Thread.currentThread().getName()+"\t修改成功否"+result+"\t当前实际最新版本号:"+ atomicStampedReference.getStamp());
            System.out.println(Thread.currentThread().getName()+"\t当前实际最新值:"+atomicStampedReference.getReference());
        },"T4").start();


    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值