内容简介:成神之路,需要耐得住寂寞,开启总结源码之旅。我阅读总结源码的目的不是为了炫技,我希望通过阅读源码可以解决一些问题,也可以通过阅读源码理解别人思想,以帮助我们更好的写我们的代码。在多线程的场景中,我们需要如何同步数据,通常会使用synchronized或者lock来处理,使用了synchronized意味着内核态的一次切换。这是一个很重的操作。有没有一种方式,可以比较便利的实现一些简单的数据同步,比如计数器等等。concurrent包下的atomic提供我们这么一种轻量级的数据同步的选择。
成神之路,需要耐得住寂寞,开启总结源码之旅。
我阅读总结源码的目的不是为了炫技,我希望通过阅读源码可以解决一些问题,也可以通过阅读源码理解别人思想,以帮助我们更好的写我们的代码。
引子
在多线程的场景中,我们需要如何同步数据,通常会使用synchronized或者lock来处理,使用了synchronized意味着内核态的一次切换。这是一个很重的操作。有没有一种方式,可以比较便利的实现一些简单的数据同步,比如计数器等等。concurrent包下的atomic提供我们这么一种轻量级的数据同步的选择。
他山之石
- 说一说 Java 的Unsafe类: www.cnblogs.com/pkufork/p/j…
- java魔法之unsafe: leokongwq.github.io/2016/12/31/…
- java乐观锁实现案例: blog.csdn.net/zhangdehua6…
- Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS: www.cnblogs.com/qjjazry/p/6…
- JDK8系列之LongAdder解析: www.jianshu.com/p/ec045c38e…
- jdk1.8 LongAdder源码学习: blog.csdn.net/u011392897/…
使用例子
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的代码
他的值是存在一个volatile的int里面。volatile只能保证这个变量的可见性。不能保证他的原子性。
可以看看getAndIncrement这个类似i++的函数,可以发现,是调用了UnSafe中的getAndAddInt。
UnSafe是何方神圣?可以参考上面的文章了解一下,UnSafe提供了java可以直接操作底层的能力。 进一步,我们可以发现实现方式:
如何保证原子性: 自旋 + CAS(乐观锁) 。在这个过程中,通过compareAndSwapInt比较更新value值,如果更新失败,重新获取旧值,然后更新。
优缺点
CAS相对于其他锁,不会进行内核态操作,有着一些性能的提升。但同时引入自旋,当锁竞争较大的时候,自旋次数会增多。cpu资源会消耗很高。
换句话说,CAS+自旋适合使用在低并发有同步数据的应用场景。
jdk8做出的改进和努力
在jdk8中引入了4个新的计数器类型,LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator。他们都是继承于Striped64。
在LongAdder 与AtomicLong有什么区别? Atomic*遇到的问题是,只能运用于低并发场景。因此LongAddr在这基础上引入了分段锁的概念。可以参考《JDK8系列之LongAdder解析》一起看看做了什么。
大概就是当竞争不激烈的时候,所有线程都是通过CAS对同一个变量(Base)进行修改,当竞争激烈的时候,会将根据当前线程哈希到对于Cell上进行修改(多段锁)。
可以看到大概实现原理是:通过 CAS乐观锁 保证原子性,通过 自旋 保证当次修改的最终修改成功,通过**降低锁粒度(多段锁)**增加并发性能。
以上所述就是小编给大家介绍的《(201)Atomic*实现原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Docker实现原理之 - OverlayFS实现原理
- 微热山丘,探索 IoC、AOP 实现原理(二) AOP 实现原理
- 带你了解vue计算属性的实现原理以及vuex的实现原理
- Docker原理之 - CGroup实现原理
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Art and Science of CSS
Jonathan Snooks、Steve Smith、Jina Bolton、Cameron Adams、David Johnson / SitePoint / March 9, 2007 / $39.95
Want to take your CSS designs to the next level? will show you how to create dozens of CSS-based Website components. You'll discover how to: # Format calendars, menus and table of contents usin......一起来看看 《The Art and Science of CSS》 这本书的介绍吧!