原子类型详解

原子类型帮助我们在多线程并发的条件下实现整数的原子操作,具有并发安全性,本文详细介绍原子类型的应用以及底层实现。

 一、无锁效率高

       无锁情况下,即使重试失败,线程始终在高速运行,没有停歇,而 synchronized 会让线程在没有获得锁的时候,发生上下文切换,进入阻塞。

       打个比喻线程就好像高速跑道上的赛车,高速运行时,速度超快,一旦发生上下文切换,就好比赛车要减速、熄火,等被唤醒又得重新打火、启动、加速…恢复到高速运行,代价比较大

       但无锁情况下,因为线程要保持运行,需要额外 CPU 的支持, CPU 在这里就好比高速跑道,没有额外的跑道,线程想高速运行也无从谈起,虽然不会进入阻塞,但由于没有分到时间片,仍然会进入可运行状态,还是会导致上下文切换。

      简单来说,开锁和释放锁的代价明显要高,所以我们需要一种无锁且又能保证线程安全的策略来提高并发效率。

二、CAS和volatile协作解决

CAS 的特点
结合 CAS 和 volatile 可以实现无锁并发,适用于线程数少、多核 CPU 的场景下。


CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系 我吃亏
点再重试呗

从根本上说cas并不是锁的实现,而是原子操作的一个方法,由于原子操作的特性,从而保证了并发编程的安全性。


synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。


CAS 体现的是无锁并发、无阻塞并发,请仔细体会这两句话的意思:

1、因为没有使用 synchronized ,所以线程不会陷入阻塞,这是效率提升的因素之一


2、但如果竞争激烈,可以想到重试必然频繁发生,反而效率会受影响

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

简单来说,cas是基于原子操作来保证线程安全特性,当一次尝试cas操作失败后,会进入无限循环之中,直到cas成功。也就是说,在失败的情况下,cas会持续占用cpu时间片。也就是说,当多个线程竞争时,由于某个变量的频繁改变,可能会导致线程始终处在执行cas的阶段而无法执行接下来的任务,效率势必会下降。

三、原子类型

JUC为我们提供了许多原子类型来保证线程操作的安全性

例如

        AtomicInteger;
        AtomicBoolean;
        AtomicLong;

我们普通的数据类型在进行多线程并发时会出现变量的不安全性。例如int a  = 0;a++;

a++在我们看来只有一条语句,但翻译成字节码,会产生四条字节码指令,但由于多线程同时自加或自减,会导致字节码在排序时的错乱顺序,导致程序错误

原子类型可以解决这一矛盾大家可以看源码,会发现原子类型中并没有任何锁对象,它的底层就是依靠cas和volatile结合执行的。

以AtomicInteger为例

        AtomicInteger atomicInteger = new AtomicInteger(0);
        atomicInteger.getAndIncrement();

这样就完成了原子的自加操作。

其他的原子类型可以查阅JUC文档,与普通类型的操作类似,更能保证原子性和线程安全性

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值