视频课程
小黑屋思过中,禁止观看!
评论并刷新后可见

您需要在视频最下面评论并刷新后,方可查看完整视频

视频课程
立即观看
付费视频

您支付费用,方可查看完整视频

¥{{user.role.value}}
课程视频
开始学习
会员专享

视频合集

深入Atomic底层实现原理

  • 课程笔记
  • 问答交流

谈到原子性之前我讲到了SynchronizedReentrantLock、以及CAS ,今天深入讲Atomic的底层实现原理。

这些都是属于非常重要的内容,需要重点来掌握。

为了更好的帮助大家掌握好Atomic,这节课我会重点讲解以下4点:

1.为什么要使用Atomic?

2.Atomic有哪些常见种类?

3.Atomic涉及的常见方法?

4.Atomic的底层实现原理?

我先从Atomic的来源谈起,然后一步步深入源码,剖析底层实现原理。

为什么使用Atomic

在多线程或者并发环境中,我们常常会遇到这种情况 int i=0; i++ 稍有经验的同学都知道这种写法是线程不安全的。为了达到线程安全的目的,我们通常会用synchronized来修饰对应的代码块。现在我们有了新的方法,就是使用J.U.C包下的atomic类。
 

Atomic的种类

JDK的(concurrent包)并发包里提供了一些类来支持原子操作,如AtomicBoolean,AtomicInteger,AtomicLong都是用原子的方式来更新指定类型的值。

从多线程并行计算乐观锁 和 悲观锁 来讲,JAVA中的synchronized 属于悲观锁,即是在操作某数据的时候总是会认为多线程之间会相互干扰,属于阻塞式的加锁。

Atomic系列则属于乐观锁系列,即当操作某一段数据的时候,线程之间是不会相互影响,采用非阻塞的模式,直到更新数据的时候才会进行版本的判断是否值已经进行了修改。

深入Atomic底层实现原理-mikechen

1.基本类型类  
用于通过原子的方式更新基本类型

AtomicBoolean
原子更新布尔类型

AtomicInteger
原子更新整型

AtomicLong
原子更新长整型

2.数组  

通过原子的方式更新数组里的某个元素
AtomicIntegerArray
原子更新整型数组里的元素

AtomicLongArray
原子更新长整型数组里的元素

AtomicReferenceArray
原子更新引用类型数组里的元素

3.引用类型 
如果要原子的更新多个变量,就需要使用这个原子更新引用类型提供的类

AtomicReference
原子更新引用类型

AtomicReferenceFieldUpdater
原子更新引用类型里的字段

AtomicMarkableReference
原子更新带有标记位的引用类型

4.字段类  
如果我们只需要某个类里的某个字段,那么就需要使用原子更新字段类

AtomicIntegerFieldUpdater
原子更新整型的字段的更新器

AtomicLongFieldUpdater
原子更新长整型字段的更新器

AtomicStampedReference
原子更新带有版本号的引用类型

5.JDK1.8新增XXXAdder
LongAdder

Atomic的常用的方法

//获取当前的值


public final int get()


//取当前的值,并设置新的值


public final int getAndSet(int newValue)


//获取当前的值,并自增


public final int getAndIncrement()


//获取当前的值,并自减


public final int getAndDecrement()


//获取当前的值,并加上预期的值


public final int getAndAdd(int delta)

Atomic的实现原理

通过自旋CAS操作volatile变量实现的。

  • CAS是compare and swap的缩写,即比较后(比较内存中的旧值与预期值)交换(将旧值替换成预期值)。它是sun.misc包下Unsafe类提供的功能,需要底层硬件指令集的支撑。
  • 使用volatile变量是为了多个线程间变量的值能及时同步。
评论交流
  1. 路正银

    当低并发时,Atomic效率优于synchronized
    当高并发时,synchronized效率优于Atomic
    synchronized重量级操作,是悲观锁;Atomic是乐观锁,基于volitile和CAS实现,当并发量大时,CAS失败的概率会增大,自旋次数增多,浪费cpu时间,效率会降低
    低并发时LongAdder和AtomicLong性能差不多,高并发时LongAdder更高效
    低并发环境下,LongAdder执行的是casBase操作类似于AtomicLong的cas操作;AtomicLong在高并发情况之下,CAS失败几率更高,重试次数更多,越多线程重试,CAS失败几率又越高,变成恶性循环,AtomicLong效率降低。LongAdder给出的解决方案是:减少并发,将单一value的更新压力分担到多个value中去,降低单个value的“热度”,分段更新。这样,线程数再多也会分担到多个value上去更新,只需要增加value就可以降低value的热度。

  2. 李鸿翼

    sync:300:29 atomic:300:27
    sync:3000:236 atomic:3000:228
    sync:120000:8797 atomic:120000:8679
    sync:220000:15726 atomic:220000:15974
    sync:320000:23008 atomic:320000:22934
    线程少的时候,atomic弱优于synchronized, 随着并发增大,相差还是不明显,但在继续增大过程过,偶尔出现弱于synchronized情况出现。

    估计synchronized有自旋优化的原因,所以和atomic相差不明显,甚至偶尔出现优势。

    AtomicLong:50000:3945 LongAddr:50000:3895
    AtomicLong:100000:7519 LongAddr:100000:7425
    AtomicLong:100:10 LongAddr:100:12
    AtomicLong:500:46 LongAddr:500:43

    从数据看,LongAddr优于AtomicLong,简单看了下代码,他们本质技术都是基于cas,但是LongAddr用数组拆分了这个value值, 降低了cas更新失败的可能性。