zoukankan      html  css  js  c++  java
  • Java多线程系列--“JUC原子类”02之 AtomicLong原子类

    概要

    AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似。本章以AtomicLong对基本类型的原子类进行介绍。内容包括:
    AtomicLong介绍和函数列表
    AtomicLong源码分析(基于JDK1.7.0_40)
    AtomicLong示例

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514593.html

    AtomicLong介绍和函数列表

    AtomicLong是作用是对长整形进行原子操作。
    在32位操作系统中,64位的long 和 double 变量由于会被JVM当作两个分离的32位来进行操作,所以不具有原子性。而使用AtomicLong能让long的操作保持原子型。

    AtomicLong函数列表

    复制代码
    // 构造函数
    AtomicLong()
    // 创建值为initialValue的AtomicLong对象
    AtomicLong(long initialValue)
    // 以原子方式设置当前值为newValue。
    final void set(long newValue) 
    // 获取当前值
    final long get() 
    // 以原子方式将当前值减 1,并返回减1后的值。等价于“--num”
    final long decrementAndGet() 
    // 以原子方式将当前值减 1,并返回减1前的值。等价于“num--”
    final long getAndDecrement() 
    // 以原子方式将当前值加 1,并返回加1后的值。等价于“++num”
    final long incrementAndGet() 
    // 以原子方式将当前值加 1,并返回加1前的值。等价于“num++”
    final long getAndIncrement()    
    // 以原子方式将delta与当前值相加,并返回相加后的值。
    final long addAndGet(long delta) 
    // 以原子方式将delta添加到当前值,并返回相加前的值。
    final long getAndAdd(long delta) 
    // 如果当前值 == expect,则以原子方式将该值设置为update。成功返回true,否则返回false,并且不修改原值。
    final boolean compareAndSet(long expect, long update)
    // 以原子方式设置当前值为newValue,并返回旧值。
    final long getAndSet(long newValue)
    // 返回当前值对应的int值
    int intValue() 
    // 获取当前值对应的long值
    long longValue()    
    // 以 float 形式返回当前值
    float floatValue()    
    // 以 double 形式返回当前值
    double doubleValue()    
    // 最后设置为给定值。延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。
    final void lazySet(long newValue)
    // 如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但不 创建任何 happen-before 排序,因此不提供与除 weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。
    final boolean weakCompareAndSet(long expect, long update)
    复制代码

    AtomicLong源码分析(基于JDK1.7.0_40)

    AtomicLong的完整源码

    复制代码
      1 /*
      2  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
      3  *
      4  *
      5  *
      6  *
      7  *
      8  *
      9  *
     10  *
     11  *
     12  *
     13  *
     14  *
     15  *
     16  *
     17  *
     18  *
     19  *
     20  *
     21  *
     22  *
     23  */
     24 
     25 /*
     26  *
     27  *
     28  *
     29  *
     30  *
     31  * Written by Doug Lea with assistance from members of JCP JSR-166
     32  * Expert Group and released to the public domain, as explained at
     33  * http://creativecommons.org/publicdomain/zero/1.0/
     34  */
     35 
     36 package java.util.concurrent.atomic;
     37 import sun.misc.Unsafe;
     38 
     39 /**
     40  * A {@code long} value that may be updated atomically.  See the
     41  * {@link java.util.concurrent.atomic} package specification for
     42  * description of the properties of atomic variables. An
     43  * {@code AtomicLong} is used in applications such as atomically
     44  * incremented sequence numbers, and cannot be used as a replacement
     45  * for a {@link java.lang.Long}. However, this class does extend
     46  * {@code Number} to allow uniform access by tools and utilities that
     47  * deal with numerically-based classes.
     48  *
     49  * @since 1.5
     50  * @author Doug Lea
     51  */
     52 public class AtomicLong extends Number implements java.io.Serializable {
     53     private static final long serialVersionUID = 1927816293512124184L;
     54 
     55     // setup to use Unsafe.compareAndSwapLong for updates
     56     private static final Unsafe unsafe = Unsafe.getUnsafe();
     57     private static final long valueOffset;
     58 
     59     /**
     60      * Records whether the underlying JVM supports lockless
     61      * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
     62      * method works in either case, some constructions should be
     63      * handled at Java level to avoid locking user-visible locks.
     64      */
     65     static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
     66 
     67     /**
     68      * Returns whether underlying JVM supports lockless CompareAndSet
     69      * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
     70      */
     71     private static native boolean VMSupportsCS8();
     72 
     73     static {
     74       try {
     75         valueOffset = unsafe.objectFieldOffset
     76             (AtomicLong.class.getDeclaredField("value"));
     77       } catch (Exception ex) { throw new Error(ex); }
     78     }
     79 
     80     private volatile long value;
     81 
     82     /**
     83      * Creates a new AtomicLong with the given initial value.
     84      *
     85      * @param initialValue the initial value
     86      */
     87     public AtomicLong(long initialValue) {
     88         value = initialValue;
     89     }
     90 
     91     /**
     92      * Creates a new AtomicLong with initial value {@code 0}.
     93      */
     94     public AtomicLong() {
     95     }
     96 
     97     /**
     98      * Gets the current value.
     99      *
    100      * @return the current value
    101      */
    102     public final long get() {
    103         return value;
    104     }
    105 
    106     /**
    107      * Sets to the given value.
    108      *
    109      * @param newValue the new value
    110      */
    111     public final void set(long newValue) {
    112         value = newValue;
    113     }
    114 
    115     /**
    116      * Eventually sets to the given value.
    117      *
    118      * @param newValue the new value
    119      * @since 1.6
    120      */
    121     public final void lazySet(long newValue) {
    122         unsafe.putOrderedLong(this, valueOffset, newValue);
    123     }
    124 
    125     /**
    126      * Atomically sets to the given value and returns the old value.
    127      *
    128      * @param newValue the new value
    129      * @return the previous value
    130      */
    131     public final long getAndSet(long newValue) {
    132         while (true) {
    133             long current = get();
    134             if (compareAndSet(current, newValue))
    135                 return current;
    136         }
    137     }
    138 
    139     /**
    140      * Atomically sets the value to the given updated value
    141      * if the current value {@code ==} the expected value.
    142      *
    143      * @param expect the expected value
    144      * @param update the new value
    145      * @return true if successful. False return indicates that
    146      * the actual value was not equal to the expected value.
    147      */
    148     public final boolean compareAndSet(long expect, long update) {
    149         return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    150     }
    151 
    152     /**
    153      * Atomically sets the value to the given updated value
    154      * if the current value {@code ==} the expected value.
    155      *
    156      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
    157      * and does not provide ordering guarantees, so is only rarely an
    158      * appropriate alternative to {@code compareAndSet}.
    159      *
    160      * @param expect the expected value
    161      * @param update the new value
    162      * @return true if successful.
    163      */
    164     public final boolean weakCompareAndSet(long expect, long update) {
    165         return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    166     }
    167 
    168     /**
    169      * Atomically increments by one the current value.
    170      *
    171      * @return the previous value
    172      */
    173     public final long getAndIncrement() {
    174         while (true) {
    175             long current = get();
    176             long next = current + 1;
    177             if (compareAndSet(current, next))
    178                 return current;
    179         }
    180     }
    181 
    182     /**
    183      * Atomically decrements by one the current value.
    184      *
    185      * @return the previous value
    186      */
    187     public final long getAndDecrement() {
    188         while (true) {
    189             long current = get();
    190             long next = current - 1;
    191             if (compareAndSet(current, next))
    192                 return current;
    193         }
    194     }
    195 
    196     /**
    197      * Atomically adds the given value to the current value.
    198      *
    199      * @param delta the value to add
    200      * @return the previous value
    201      */
    202     public final long getAndAdd(long delta) {
    203         while (true) {
    204             long current = get();
    205             long next = current + delta;
    206             if (compareAndSet(current, next))
    207                 return current;
    208         }
    209     }
    210 
    211     /**
    212      * Atomically increments by one the current value.
    213      *
    214      * @return the updated value
    215      */
    216     public final long incrementAndGet() {
    217         for (;;) {
    218             long current = get();
    219             long next = current + 1;
    220             if (compareAndSet(current, next))
    221                 return next;
    222         }
    223     }
    224 
    225     /**
    226      * Atomically decrements by one the current value.
    227      *
    228      * @return the updated value
    229      */
    230     public final long decrementAndGet() {
    231         for (;;) {
    232             long current = get();
    233             long next = current - 1;
    234             if (compareAndSet(current, next))
    235                 return next;
    236         }
    237     }
    238 
    239     /**
    240      * Atomically adds the given value to the current value.
    241      *
    242      * @param delta the value to add
    243      * @return the updated value
    244      */
    245     public final long addAndGet(long delta) {
    246         for (;;) {
    247             long current = get();
    248             long next = current + delta;
    249             if (compareAndSet(current, next))
    250                 return next;
    251         }
    252     }
    253 
    254     /**
    255      * Returns the String representation of the current value.
    256      * @return the String representation of the current value.
    257      */
    258     public String toString() {
    259         return Long.toString(get());
    260     }
    261 
    262 
    263     public int intValue() {
    264         return (int)get();
    265     }
    266 
    267     public long longValue() {
    268         return get();
    269     }
    270 
    271     public float floatValue() {
    272         return (float)get();
    273     }
    274 
    275     public double doubleValue() {
    276         return (double)get();
    277     }
    278 
    279 }
    复制代码

    AtomicLong的代码很简单,下面仅以incrementAndGet()为例,对AtomicLong的原理进行说明。
    incrementAndGet()源码如下:

    复制代码
    public final long incrementAndGet() {
        for (;;) {
            // 获取AtomicLong当前对应的long值
            long current = get();
            // 将current加1
            long next = current + 1;
            // 通过CAS函数,更新current的值
            if (compareAndSet(current, next))
                return next;
        }
    }
    复制代码

    说明
    (01) incrementAndGet()首先会根据get()获取AtomicLong对应的long值。该值是volatile类型的变量,get()的源码如下:

    // value是AtomicLong对应的long值
    private volatile long value;
    // 返回AtomicLong对应的long值
    public final long get() {
        return value;
    }

    (02) incrementAndGet()接着将current加1,然后通过CAS函数,将新的值赋值给value。
    compareAndSet()的源码如下:

    public final boolean compareAndSet(long expect, long update) {
        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    }

    compareAndSet()的作用是更新AtomicLong对应的long值。它会比较AtomicLong的原始值是否与expect相等,若相等的话,则设置AtomicLong的值为update。

    AtomicLong示例

    复制代码
     1 // LongTest.java的源码
     2 import java.util.concurrent.atomic.AtomicLong;
     3 
     4 public class LongTest {
     5     
     6     public static void main(String[] args){
     7 
     8         // 新建AtomicLong对象
     9         AtomicLong mAtoLong = new AtomicLong();
    10 
    11         mAtoLong.set(0x0123456789ABCDEFL);
    12         System.out.printf("%20s : 0x%016X
    ", "get()", mAtoLong.get());
    13         System.out.printf("%20s : 0x%016X
    ", "intValue()", mAtoLong.intValue());
    14         System.out.printf("%20s : 0x%016X
    ", "longValue()", mAtoLong.longValue());
    15         System.out.printf("%20s : %s
    ", "doubleValue()", mAtoLong.doubleValue());
    16         System.out.printf("%20s : %s
    ", "floatValue()", mAtoLong.floatValue());
    17 
    18         System.out.printf("%20s : 0x%016X
    ", "getAndDecrement()", mAtoLong.getAndDecrement());
    19         System.out.printf("%20s : 0x%016X
    ", "decrementAndGet()", mAtoLong.decrementAndGet());
    20         System.out.printf("%20s : 0x%016X
    ", "getAndIncrement()", mAtoLong.getAndIncrement());
    21         System.out.printf("%20s : 0x%016X
    ", "incrementAndGet()", mAtoLong.incrementAndGet());
    22 
    23         System.out.printf("%20s : 0x%016X
    ", "addAndGet(0x10)", mAtoLong.addAndGet(0x10));
    24         System.out.printf("%20s : 0x%016X
    ", "getAndAdd(0x10)", mAtoLong.getAndAdd(0x10));
    25 
    26         System.out.printf("
    %20s : 0x%016X
    ", "get()", mAtoLong.get());
    27 
    28         System.out.printf("%20s : %s
    ", "compareAndSet()", mAtoLong.compareAndSet(0x12345679L, 0xFEDCBA9876543210L));
    29         System.out.printf("%20s : 0x%016X
    ", "get()", mAtoLong.get());
    30     }
    31 }
    复制代码

    运行结果

    复制代码
                   get() : 0x0123456789ABCDEF
              intValue() : 0x0000000089ABCDEF
             longValue() : 0x0123456789ABCDEF
           doubleValue() : 8.1985529216486896E16
            floatValue() : 8.1985531E16
       getAndDecrement() : 0x0123456789ABCDEF
       decrementAndGet() : 0x0123456789ABCDED
       getAndIncrement() : 0x0123456789ABCDED
       incrementAndGet() : 0x0123456789ABCDEF
         addAndGet(0x10) : 0x0123456789ABCDFF
         getAndAdd(0x10) : 0x0123456789ABCDFF
    
                   get() : 0x0123456789ABCE0F
         compareAndSet() : false
                   get() : 0x0123456789ABCE0F
  • 相关阅读:
    Git 常用命令
    Python 常用算法记录
    Python基础Web服务器案例
    你真的懂SDWebImage?
    Core Data的那点事儿~
    看看 SDWebImage内部基本实现过程
    App上架流程 & 上架被拒10大原因
    KVO中你所不知道的"坑"
    math公式手写识别网址
    umi build出现的Path must be a string的问题解决
  • 原文地址:https://www.cnblogs.com/wzyxidian/p/5307104.html
Copyright © 2011-2022 走看看