JUC并发包下原子操作类Atomic和LongAdder详解

Atomic和LongAdder详解

Atomic顾名思义原子类,肯定是不可分割的,那JDK为什么要设计这样的类呢。这我们要讲到多线程问题了。

当有多个线程时,访问同一个共享变量,如不经做一些安全措施将会发生一些不可描述的事。所以我们必须要对这个共享变量加锁,之前加锁都是Synchronized,但Synchronized有一些问题,它要经过用户态到内核态的调用,开销很大,这里不说Synchronized升级。开销很大怎么办呢,下面就出来我们要讲的重点了:CAS。全程:Compare and Swap,它是JDK提供的非阻塞原子性操纵,它通过硬件保证了比较–更新操纵的原子性。

CAS的意思是比较并交换。CAS有四个操作数,分别为:对象内存位置,对象中的变量的偏移量,变量预期值和新的值。其操作含义是:如果对象obj中内存偏移量为valueOffset的变量值为expect,则使用新的值pudate替换旧的值expect.

JDK中的Atomic系列都是非阻塞CAS实现的,其内部使用的是unsafe类。我们来看些递增和递减的源码:
JUC并发包下原子操作类Atomic和LongAdder详解
JUC并发包下原子操作类Atomic和LongAdder详解
但Atomic类通过CAS提供了非阻塞的原子性操纵,相比阻塞算法的同步器来说它的性能已经很好了,但JDK开发组并不满足于此。因为使用Atomic时,如果在高并发情况下同时竞争更新同一个原子变量,但同时只有一个线程的CAS操作才会成功,这就造就了大量线程竞争失败后开始自旋,CAS自旋是占用CPU的。
怎么克服这个缺点呢,JDK1.8新增了一个原子性递增或递减类LongAdder用来克服这个缺点,首先Atomic类的缺点在于多个线程争强同一个变量,LongAdder就是把这一个变量分成了多个变量,让线程争强时,这个变量正在被持有,可以去抢另一个变量,这样就解决了Atomic带来的缺点。