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的完整源码

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()源码如下:

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\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

 


更多内容

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

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

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

 

你可能感兴趣的:(AtomicLong)