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函数列表

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

 

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

AtomicLongArray的完整源码

Java多线程系列--“JUC原子类”03之 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()源码如下:

Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类
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;
    }
}
Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

说明: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示例

Java多线程系列--“JUC原子类”03之 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\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 }
Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

运行结果

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

 


更多内容

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

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

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

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

上一篇:Arduino网络编程实战-Ethernet篇-MQTT客户端


下一篇:【MQTT入门】基础——发布和订阅