CAS原子操作

原子操作

什么是原子操作,打个比方,假如有两个操作A和B,当执行A的线程去看另一个执行B的线程的时候,要么B线程还没执行,要么B线程执行完了。那么A跟B之间就是原子的。

如何实现原子操作

实现原子操作的方式,当然有加锁,比如synchronized加锁机制可以很好的保证原子操作,但是过于笨重。
例如,当一个线程占有锁的时候,其他的线程就必须等这个线程把锁释放了才能运行。 那如果 被阻塞的线程是优先级较高的话怎么办。还有就是cpu也会花费大量时间和资源来处理这些竞争。还有可能出现死锁之类的情况。

当然了实现原子操作还可以使用当前处理机基本都支持的cas指令。只不过每 个厂家所实现的算法并不一样。

CAS

每一个cas操作过程都包括 :

  • 一个内存地址 (假设为V)
  • 一个期望的值 (假设为A)
  • 一个新的值 (假设为B)

操作的时候,如果这个地址上存放的值V等于这个期望的值A,那么则将地址上的值赋值为B,否则不做操作。其实就是拿内存地址对比旧值,如果内存地址的值跟旧值一样,那么证明这个值没有被其他线程更改过。如果cas指令操作不成功,则一直循环,直到成功为止。

cas的几个问题

1 、
因为在CAS的操作时,会检查值有没有变化,如果没有变化则更新。但是如果一个值从A变成了B,又从B变成了A,但是其他线程cas检查的时候发现值没有变化,但实际上是已经变化过了。

这就比如,你倒了一杯水放桌子上,干了点别的事,然后同事把你水喝了又给你重新 倒了一杯水,你回来看水还在,拿起来就喝,如果你不管水中间被人喝过,只关 心水还在,这就是 ABA 问题。

解决的方式就是,你在杯子上写个 1,当这杯子有变动的时候,会把杯子的值累加1,那么你要确认这个被子里的水是不是你当初的那杯,没有被人动过,看编号就知道了。

2、
循环的时间开销,假设 cas自旋长时间不成功,会给cpu带来大的执行开销

3、
只能保证一个共享变量的原子操作。
当对一个共享变量执行操作时,我们可以使用循环 CAS 的方式来保证原子操 作,但是对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候 就可以用锁。

jdk中相关原子操作类的使用
public class Demo17 {
    public static void main(String[] args) {

        AtomicInteger atomicInteger = new AtomicInteger();
        AtomicBoolean atomicBoolean = new AtomicBoolean();
        AtomicDouble atomicDouble = new AtomicDouble();
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
        //等等。。等等。。
    }
}

原子更新基本类型的 AtomicInteger,只能更新一个变量,如果要原子更新多 个变量,就需要使用这个原子更新引用类型提供的类。Atomic 包提供了以下 3 个类。

  • AtomicReference
    原子更新引用类型。
  • AtomicStampedReference
    利用版本戳的形式记录了每次改变以后的版本号, 意思就是关心动过了几次。
  • AtomicMarkableReference
    关心的就是有没有被人动过
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值