Java多线程系列--“JUC原子类”02之 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      * 

May fail spuriously 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 }

复制代码

 

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) 
14             System.out.printf("get(%d) : %s\n", i, ala.get(i));
15 
16         System.out.printf("%20s : %s\n", "getAndDecrement(0)", ala.getAndDecrement(0));
17         System.out.printf("%20s : %s\n", "decrementAndGet(1)", ala.decrementAndGet(1));
18         System.out.printf("%20s : %s\n", "getAndIncrement(2)", ala.getAndIncrement(2));
19         System.out.printf("%20s : %s\n", "incrementAndGet(3)", ala.incrementAndGet(3));
20 
21         System.out.printf("%20s : %s\n", "addAndGet(100)", ala.addAndGet(0, 100));
22         System.out.printf("%20s : %s\n", "getAndAdd(100)", ala.getAndAdd(1, 100));
23 
24         System.out.printf("%20s : %s\n", "compareAndSet()", ala.compareAndSet(2, 31, 1000));
25         System.out.printf("%20s : %s\n", "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
复制代码

你可能感兴趣的:(JAVA并发编程)