(201)Atomic*实现原理

栏目: Java · 发布时间: 6年前

内容简介:成神之路,需要耐得住寂寞,开启总结源码之旅。我阅读总结源码的目的不是为了炫技,我希望通过阅读源码可以解决一些问题,也可以通过阅读源码理解别人思想,以帮助我们更好的写我们的代码。在多线程的场景中,我们需要如何同步数据,通常会使用synchronized或者lock来处理,使用了synchronized意味着内核态的一次切换。这是一个很重的操作。有没有一种方式,可以比较便利的实现一些简单的数据同步,比如计数器等等。concurrent包下的atomic提供我们这么一种轻量级的数据同步的选择。

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

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

引子

在多线程的场景中,我们需要如何同步数据,通常会使用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的代码

(201)Atomic*实现原理

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

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

(201)Atomic*实现原理

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

(201)Atomic*实现原理

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

优缺点

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

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

jdk8做出的改进和努力

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

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

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

(201)Atomic*实现原理

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


以上所述就是小编给大家介绍的《(201)Atomic*实现原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Science of Programming

The Science of Programming

David Gries / Springer / 1989-4-21 / USD 99.00

Describes basic programming principles and their step-by- step applications.Numerous examples are included.一起来看看 《The Science of Programming》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具