zoukankan      html  css  js  c++  java
  • java中原子操作的实现分析

    一、CAS原理:

    CAS的全程即Compare And Swap,翻译成中文为比较并交换;

    CAS操作依赖于CPU指令CMPXCHG来实现比较并交换操作的原子性,通过查看HotSpot源码如下:

     

    可以看到这个实现跟CPU的类型相关,程序会根据当前处理器的类型来决定是否为cmpxchg指令添加lock前缀。如果程序是在多处理器上运行,就为cmpxchg指令加上lock前缀(lock cmpxchg)。反之,如果程序是在单处理器上运行,就省略lock前缀(单处理器自身会维护单处理器内的顺序一致性,不需要lock前缀提供的内存屏障效果)。

    二、AtomicInteger源码分析:

    以AtomicInteger类的实现源码分析,其他原子操作类的代码类似;

    AtomicInteger封装了对int类型的原子操作,通过类的接口操作int数据都是原子性的,不会造成在多线程环境中脏数据的读写;实现int的原子操作是通过unsafe接口函数操作完成的(比如putOrderedInt、compareAndSwapInt等),unsafe接口函数都是本地函数;

    在AtomicInteger类中定义了一个int类型的变量:

     

    接口函数:

    getAndSet:

     

    调用compareAndSet比较current和value值是否相等,如果相等就设置为newValue并返回True,否则返回False;

    如果compareAndSet返回false,则说明value值已经是脏数据(被其他线程修改过),因此会一直循环下去,直至compareAndSet返回True则返回;

    getAndIncrement

     

    与上面的类似,如果compareAndSet返回false,则会一致循环下去,直至compareAndSet返回True则返回;

    同样的效果也能通过锁来达到,但是原子操作的开销比锁的开销小很多; 

    incrementAndGet

     

    与上面的类似,如果compareAndSet返回false,则会一致循环下去,直至compareAndSet返回True则返回;

     

    compareAndSet调用了unsafe.compareAndSwapInt,unsafe.compareAndSwapInt是本地方法,调用操作系统原生程序;通过查看jdk源码发现其实是调用了CMPXCHG指令;

    由于AtomicInteger采用了无限循环的方式来操作,因此称作自旋CAS方式;CAS方式存在三大问题:

    1、ABA问题:因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。

    从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

          public boolean compareAndSet (V expectedReference,//预期引用

                                    V newReference,//更新后的引用

                                    int expectedStamp, //预期标志

                          int newStamp) //更新后的标志

    2、循环时间长开销大:自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。

    3、只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作。

  • 相关阅读:
    C#中的?问号
    佛学中的108条做人道理
    SQL Server函数总结
    ASP.NET MVC与Web Forms
    常数定义和字段定义的区别
    What is the purpose of Entity Framework T4 template.
    ASP.NET Internals – IIS and the Process Model
    asp.net为什么没有多重继承(个人观点,欢迎指正,谢谢!)
    c#委托,事件及观察者模式(转自:http://www.cnblogs.com/JimmyZhang/archive/2011/12/25/903360.html)
    GC and Memory leak
  • 原文地址:https://www.cnblogs.com/laoxia/p/8046779.html
Copyright © 2011-2022 走看看