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

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

 

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\n", "get()", mAtoLong.get());

13         System.out.printf("%20s : 0x%016X\n", "intValue()", mAtoLong.intValue());

14         System.out.printf("%20s : 0x%016X\n", "longValue()", mAtoLong.longValue());

15         System.out.printf("%20s : %s\n", "doubleValue()", mAtoLong.doubleValue());

16         System.out.printf("%20s : %s\n", "floatValue()", mAtoLong.floatValue());

17 

18         System.out.printf("%20s : 0x%016X\n", "getAndDecrement()", mAtoLong.getAndDecrement());

19         System.out.printf("%20s : 0x%016X\n", "decrementAndGet()", mAtoLong.decrementAndGet());

20         System.out.printf("%20s : 0x%016X\n", "getAndIncrement()", mAtoLong.getAndIncrement());

21         System.out.printf("%20s : 0x%016X\n", "incrementAndGet()", mAtoLong.incrementAndGet());

22 

23         System.out.printf("%20s : 0x%016X\n", "addAndGet(0x10)", mAtoLong.addAndGet(0x10));

24         System.out.printf("%20s : 0x%016X\n", "getAndAdd(0x10)", mAtoLong.getAndAdd(0x10));

25 

26         System.out.printf("\n%20s : 0x%016X\n", "get()", mAtoLong.get());

27 

28         System.out.printf("%20s : %s\n", "compareAndSet()", mAtoLong.compareAndSet(0x12345679L, 0xFEDCBA9876543210L));

29         System.out.printf("%20s : 0x%016X\n", "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

 


更多内容

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

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

 

你可能感兴趣的:(AtomicLong)