(201)Atomic*实现原理

作者: 林湾村龙猫 | 来源:发表于2018-09-10 15:28 被阅读17次

成神之路,需要耐得住寂寞,开启总结源码之旅。

我阅读总结源码的目的不是为了炫技,我希望通过阅读源码可以解决一些问题,也可以通过阅读源码理解别人思想,以帮助我们更好的写我们的代码。

引子

在多线程的场景中,我们需要如何同步数据,通常会使用synchronized或者lock来处理,使用了synchronized意味着内核态的一次切换。这是一个很重的操作。有没有一种方式,可以比较便利的实现一些简单的数据同步,比如计数器等等。concurrent包下的atomic提供我们这么一种轻量级的数据同步的选择。

他山之石

使用例子

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class App {

    public static void main(String[] args) throws Exception {
        CountDownLatch countDownLatch = new CountDownLatch(100);

        AtomicInteger atomicInteger = new AtomicInteger(0);
        for (int i = 0; i < 100; i++) {
            new Thread() {
                @Override
                public void run() {
                    atomicInteger.getAndIncrement();

                    countDownLatch.countDown();
                }
            }.start();
        }

        countDownLatch.await();

        System.out.println(atomicInteger.get());
    }
}

请暂时先忽略CountDownLatch,只是为了在主线程中等待所有子线程执行完,打印结果。这个结果永远都是100。如果将AtomicInteger换成Integer,打印结果基本都是小于100。

原理

我们可以看一下AtomicInteger的代码


image.png

他的值是存在一个volatile的int里面。volatile只能保证这个变量的可见性。不能保证他的原子性。

可以看看getAndIncrement这个类似i++的函数,可以发现,是调用了UnSafe中的getAndAddInt。


image.png

UnSafe是何方神圣?可以参考上面的文章了解一下,UnSafe提供了java可以直接操作底层的能力。
进一步,我们可以发现实现方式:


image.png

如何保证原子性:自旋 + CAS(乐观锁)。在这个过程中,通过compareAndSwapInt比较更新value值,如果更新失败,重新获取旧值,然后更新。

优缺点

CAS相对于其他锁,不会进行内核态操作,有着一些性能的提升。但同时引入自旋,当锁竞争较大的时候,自旋次数会增多。cpu资源会消耗很高。

换句话说,CAS+自旋适合使用在低并发有同步数据的应用场景。

jdk8做出的改进和努力

在jdk8中引入了4个新的计数器类型,LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator。他们都是继承于Striped64。

在LongAdder 与AtomicLong有什么区别?
Atomic*遇到的问题是,只能运用于低并发场景。因此LongAddr在这基础上引入了分段锁的概念。可以参考《JDK8系列之LongAdder解析》一起看看做了什么。

大概就是当竞争不激烈的时候,所有线程都是通过CAS对同一个变量(Base)进行修改,当竞争激烈的时候,会将根据当前线程哈希到对于Cell上进行修改(多段锁)。


image.png

可以看到大概实现原理是:通过CAS乐观锁保证原子性,通过自旋保证当次修改的最终修改成功,通过降低锁粒度(多段锁)增加并发性能。

关键点

  • 自旋
  • CAS乐观锁
  • 多段锁(分治思想)

相关文章

  • (201)Atomic*实现原理

    成神之路,需要耐得住寂寞,开启总结源码之旅。 我阅读总结源码的目的不是为了炫技,我希望通过阅读源码可以解决一些问题...

  • 4-6 ARC以及修饰符

    修饰符 atomic 是绝对的线程安全吗? retain实现原理 release实现原理 dealloc 实现原理...

  • 阻塞队列LinkedBlockingQueue原理简析

    前言 分析LinkedBlockingQueue的实现原理前,需要先了解ReentrantLock 和Atomic...

  • Java并发机制底层实现(三)

    原子操作实现原理 概念 原子(atomic)本意是"不能被进一步分割的最小粒子",而原子操作(atomic ope...

  • J.U.C

    1 atomic 类 AtomicInteger内部原理:底层利用硬件cas实现原子的比较和修改Unsafe.co...

  • CAS机制

    还有就是这个atomic包,使用可以达到synchronized的效果,实现原理就是CAS了。 CAS也叫自旋锁,...

  • sqlite:WAL模式

    工作原理 默认情况下,sqlite通过回滚日志来实现事物的原子性提交(atomic commit and roll...

  • 题库整理(一)

    1.atomic和nonatomic的区别?atomic一定是线程安全的吗?atomic如何实现atomic? a...

  • golang sync.once解析

    实现原理(当前代码版本go version go1.11.4 ) 1.atomic 原子操作计数器,用于记录此On...

  • java Atomic原子操作实现原理

    今天在看kafka源码的时候有这样一段代码 其中上面的 isStartingUp 是 AtomicBoolean ...

网友评论

    本文标题:(201)Atomic*实现原理

    本文链接:https://www.haomeiwen.com/subject/blplwftx.html