• Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类


    概要

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

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

    AtomicLongArray介绍和函数列表

    在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操作。而AtomicLongArray的作用则是对"长整形数组"进行原子操作。

    AtomicLongArray函数列表

    // 创建给定长度的新 AtomicLongArray。
    AtomicLongArray(int length)
    // 创建与给定数组具有相同长度的新 AtomicLongArray,并从给定数组复制其所有元素。
    AtomicLongArray(long[] array)
    
    // 以原子方式将给定值添加到索引 i 的元素。
    long addAndGet(int i, long delta)
    // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
    boolean compareAndSet(int i, long expect, long update)
    // 以原子方式将索引 i 的元素减1。
    long decrementAndGet(int i)
    // 获取位置 i 的当前值。
    long get(int i)
    // 以原子方式将给定值与索引 i 的元素相加。
    long getAndAdd(int i, long delta)
    // 以原子方式将索引 i 的元素减 1。
    long getAndDecrement(int i)
    // 以原子方式将索引 i 的元素加 1。
    long getAndIncrement(int i)
    // 以原子方式将位置 i 的元素设置为给定值,并返回旧值。
    long getAndSet(int i, long newValue)
    // 以原子方式将索引 i 的元素加1。
    long incrementAndGet(int i)
    // 最终将位置 i 的元素设置为给定值。
    void lazySet(int i, long newValue)
    // 返回该数组的长度。
    int length()
    // 将位置 i 的元素设置为给定值。
    void set(int i, long newValue)
    // 返回数组当前值的字符串表示形式。
    String toString()
    // 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
    boolean    weakCompareAndSet(int i, long expect, long update)

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

    AtomicLongArray的完整源码

      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 import java.util.*;
     39 
     40 /**
     41  * A {@code long} array in which elements may be updated atomically.
     42  * See the {@link java.util.concurrent.atomic} package specification
     43  * for description of the properties of atomic variables.
     44  * @since 1.5
     45  * @author Doug Lea
     46  */
     47 public class AtomicLongArray implements java.io.Serializable {
     48     private static final long serialVersionUID = -2308431214976778248L;
     49 
     50     private static final Unsafe unsafe = Unsafe.getUnsafe();
     51     private static final int base = unsafe.arrayBaseOffset(long[].class);
     52     private static final int shift;
     53     private final long[] array;
     54 
     55     static {
     56         int scale = unsafe.arrayIndexScale(long[].class);
     57         if ((scale & (scale - 1)) != 0)
     58             throw new Error("data type scale not a power of two");
     59         shift = 31 - Integer.numberOfLeadingZeros(scale);
     60     }
     61 
     62     private long checkedByteOffset(int i) {
     63         if (i < 0 || i >= array.length)
     64             throw new IndexOutOfBoundsException("index " + i);
     65 
     66         return byteOffset(i);
     67     }
     68 
     69     private static long byteOffset(int i) {
     70         return ((long) i << shift) + base;
     71     }
     72 
     73     /**
     74      * Creates a new AtomicLongArray of the given length, with all
     75      * elements initially zero.
     76      *
     77      * @param length the length of the array
     78      */
     79     public AtomicLongArray(int length) {
     80         array = new long[length];
     81     }
     82 
     83     /**
     84      * Creates a new AtomicLongArray with the same length as, and
     85      * all elements copied from, the given array.
     86      *
     87      * @param array the array to copy elements from
     88      * @throws NullPointerException if array is null
     89      */
     90     public AtomicLongArray(long[] array) {
     91         // Visibility guaranteed by final field guarantees
     92         this.array = array.clone();
     93     }
     94 
     95     /**
     96      * Returns the length of the array.
     97      *
     98      * @return the length of the array
     99      */
    100     public final int length() {
    101         return array.length;
    102     }
    103 
    104     /**
    105      * Gets the current value at position {@code i}.
    106      *
    107      * @param i the index
    108      * @return the current value
    109      */
    110     public final long get(int i) {
    111         return getRaw(checkedByteOffset(i));
    112     }
    113 
    114     private long getRaw(long offset) {
    115         return unsafe.getLongVolatile(array, offset);
    116     }
    117 
    118     /**
    119      * Sets the element at position {@code i} to the given value.
    120      *
    121      * @param i the index
    122      * @param newValue the new value
    123      */
    124     public final void set(int i, long newValue) {
    125         unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
    126     }
    127 
    128     /**
    129      * Eventually sets the element at position {@code i} to the given value.
    130      *
    131      * @param i the index
    132      * @param newValue the new value
    133      * @since 1.6
    134      */
    135     public final void lazySet(int i, long newValue) {
    136         unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
    137     }
    138 
    139 
    140     /**
    141      * Atomically sets the element at position {@code i} to the given value
    142      * and returns the old value.
    143      *
    144      * @param i the index
    145      * @param newValue the new value
    146      * @return the previous value
    147      */
    148     public final long getAndSet(int i, long newValue) {
    149         long offset = checkedByteOffset(i);
    150         while (true) {
    151             long current = getRaw(offset);
    152             if (compareAndSetRaw(offset, current, newValue))
    153                 return current;
    154         }
    155     }
    156 
    157     /**
    158      * Atomically sets the element at position {@code i} to the given
    159      * updated value if the current value {@code ==} the expected value.
    160      *
    161      * @param i the index
    162      * @param expect the expected value
    163      * @param update the new value
    164      * @return true if successful. False return indicates that
    165      * the actual value was not equal to the expected value.
    166      */
    167     public final boolean compareAndSet(int i, long expect, long update) {
    168         return compareAndSetRaw(checkedByteOffset(i), expect, update);
    169     }
    170 
    171     private boolean compareAndSetRaw(long offset, long expect, long update) {
    172         return unsafe.compareAndSwapLong(array, offset, expect, update);
    173     }
    174 
    175     /**
    176      * Atomically sets the element at position {@code i} to the given
    177      * updated value if the current value {@code ==} the expected value.
    178      *
    179      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
    180      * and does not provide ordering guarantees, so is only rarely an
    181      * appropriate alternative to {@code compareAndSet}.
    182      *
    183      * @param i the index
    184      * @param expect the expected value
    185      * @param update the new value
    186      * @return true if successful.
    187      */
    188     public final boolean weakCompareAndSet(int i, long expect, long update) {
    189         return compareAndSet(i, expect, update);
    190     }
    191 
    192     /**
    193      * Atomically increments by one the element at index {@code i}.
    194      *
    195      * @param i the index
    196      * @return the previous value
    197      */
    198     public final long getAndIncrement(int i) {
    199         return getAndAdd(i, 1);
    200     }
    201 
    202     /**
    203      * Atomically decrements by one the element at index {@code i}.
    204      *
    205      * @param i the index
    206      * @return the previous value
    207      */
    208     public final long getAndDecrement(int i) {
    209         return getAndAdd(i, -1);
    210     }
    211 
    212     /**
    213      * Atomically adds the given value to the element at index {@code i}.
    214      *
    215      * @param i the index
    216      * @param delta the value to add
    217      * @return the previous value
    218      */
    219     public final long getAndAdd(int i, long delta) {
    220         long offset = checkedByteOffset(i);
    221         while (true) {
    222             long current = getRaw(offset);
    223             if (compareAndSetRaw(offset, current, current + delta))
    224                 return current;
    225         }
    226     }
    227 
    228     /**
    229      * Atomically increments by one the element at index {@code i}.
    230      *
    231      * @param i the index
    232      * @return the updated value
    233      */
    234     public final long incrementAndGet(int i) {
    235         return addAndGet(i, 1);
    236     }
    237 
    238     /**
    239      * Atomically decrements by one the element at index {@code i}.
    240      *
    241      * @param i the index
    242      * @return the updated value
    243      */
    244     public final long decrementAndGet(int i) {
    245         return addAndGet(i, -1);
    246     }
    247 
    248     /**
    249      * Atomically adds the given value to the element at index {@code i}.
    250      *
    251      * @param i the index
    252      * @param delta the value to add
    253      * @return the updated value
    254      */
    255     public long addAndGet(int i, long delta) {
    256         long offset = checkedByteOffset(i);
    257         while (true) {
    258             long current = getRaw(offset);
    259             long next = current + delta;
    260             if (compareAndSetRaw(offset, current, next))
    261                 return next;
    262         }
    263     }
    264 
    265     /**
    266      * Returns the String representation of the current values of array.
    267      * @return the String representation of the current values of array
    268      */
    269     public String toString() {
    270         int iMax = array.length - 1;
    271         if (iMax == -1)
    272             return "[]";
    273 
    274         StringBuilder b = new StringBuilder();
    275         b.append('[');
    276         for (int i = 0; ; i++) {
    277             b.append(getRaw(byteOffset(i)));
    278             if (i == iMax)
    279                 return b.append(']').toString();
    280             b.append(',').append(' ');
    281         }
    282     }
    283 
    284 }
    View Code

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

    public final long incrementAndGet(int i) {
        return addAndGet(i, 1);
    }

    说明:incrementAndGet()的作用是以原子方式将long数组的索引 i 的元素加1,并返回加1之后的值。

    addAndGet()源码如下:

    public long addAndGet(int i, long delta) {
        // 检查数组是否越界
        long offset = checkedByteOffset(i);
        while (true) {
            // 获取long型数组的索引 offset 的原始值
            long current = getRaw(offset);
            // 修改long型值
            long next = current + delta;
            // 通过CAS更新long型数组的索引 offset的值。
            if (compareAndSetRaw(offset, current, next))
                return next;
        }
    }

    说明:addAndGet()首先检查数组是否越界。如果没有越界的话,则先获取数组索引i的值;然后通过CAS函数更新i的值。

    getRaw()源码如下:

    private long getRaw(long offset) {
        return unsafe.getLongVolatile(array, offset);
    }

    说明:unsafe是通过Unsafe.getUnsafe()返回的一个Unsafe对象。通过Unsafe的CAS函数对long型数组的元素进行原子操作。如compareAndSetRaw()就是调用Unsafe的CAS函数,它的源码如下:

    private boolean compareAndSetRaw(long offset, long expect, long update) {
        return unsafe.compareAndSwapLong(array, offset, expect, update);
    }

    AtomicLongArray示例

     1 // LongArrayTest.java的源码
     2 import java.util.concurrent.atomic.AtomicLongArray;
     3 
     4 public class LongArrayTest {
     5     
     6     public static void main(String[] args){
     7 
     8         // 新建AtomicLongArray对象
     9         long[] arrLong = new long[] {10, 20, 30, 40, 50};
    10         AtomicLongArray ala = new AtomicLongArray(arrLong);
    11 
    12         ala.set(0, 100);
    13         for (int i=0, len=ala.length(); i<len; i++) 
    14             System.out.printf("get(%d) : %s
    ", i, ala.get(i));
    15 
    16         System.out.printf("%20s : %s
    ", "getAndDecrement(0)", ala.getAndDecrement(0));
    17         System.out.printf("%20s : %s
    ", "decrementAndGet(1)", ala.decrementAndGet(1));
    18         System.out.printf("%20s : %s
    ", "getAndIncrement(2)", ala.getAndIncrement(2));
    19         System.out.printf("%20s : %s
    ", "incrementAndGet(3)", ala.incrementAndGet(3));
    20 
    21         System.out.printf("%20s : %s
    ", "addAndGet(100)", ala.addAndGet(0, 100));
    22         System.out.printf("%20s : %s
    ", "getAndAdd(100)", ala.getAndAdd(1, 100));
    23 
    24         System.out.printf("%20s : %s
    ", "compareAndSet()", ala.compareAndSet(2, 31, 1000));
    25         System.out.printf("%20s : %s
    ", "get(2)", ala.get(2));
    26     }
    27 }

    运行结果

    get(0) : 100
    get(1) : 20
    get(2) : 30
    get(3) : 40
    get(4) : 50
      getAndDecrement(0) : 100
      decrementAndGet(1) : 19
      getAndIncrement(2) : 30
      incrementAndGet(3) : 41
          addAndGet(100) : 199
          getAndAdd(100) : 19
         compareAndSet() : true
                  get(2) : 1000

    更多内容

    1. Java多线程系列--“JUC原子类”01之 框架

    2. Java多线程系列--“JUC原子类”02之 AtomicLong原子类

    3. Java多线程系列目录(共xx篇)

  • 相关阅读:
    算法
    什么叫「人的格局」?是否有必要培养大的格局或怎么培养?
    套接字
    信号量 P V测试详解
    Emacs快速入门
    Emacs 从入门到精通
    Linux多进程之间的文件锁
    mysql 登录报错:ERROR 1045 (28000)
    类职责协作模型
    .Netcore使用Session
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3514604.html
Copyright © 2020-2023  润新知