[Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析
Atomic原子類:為基本類型的封裝類Boolean,Integer,Long,對象引用等提供原子操作.
一、Atomic包下的所有類如下表:
| 類摘要 | |
| AtomicBoolean | 可以用原子方式更新的?boolean?值。 |
| AtomicInteger | 可以用原子方式更新的?int?值。 |
| AtomicIntegerArray | 可以用原子方式更新其元素的?int?數組。 |
| AtomicIntegerFieldUpdater<T> | 基于反射的實用工具,可以對指定類的指定?volatile int?字段進行原子更新。 |
| AtomicLong | 可以用原子方式更新的?long?值。 |
| AtomicLongArray | 可以用原子方式更新其元素的?long?數組。 |
| AtomicLongFieldUpdater<T> | 基于反射的實用工具,可以對指定類的指定?volatile long?字段進行原子更新。 |
| AtomicMarkableReference<V> | AtomicMarkableReference?維護帶有標記位的對象引用,可以原子方式對其進行更新。 |
| AtomicReference<V> | 可以用原子方式更新的對象引用。 |
| AtomicReferenceArray<E> | 可以用原子方式更新其元素的對象引用數組。 |
| AtomicReferenceFieldUpdater<T,V> | 基于反射的實用工具,可以對指定類的指定?volatile?字段進行原子更新。 |
| AtomicStampedReference<V> | AtomicStampedReference?維護帶有整數“標志”的對象引用,可以用原子方式對其進行更新。 |
?
二、AtomicInteger源碼分析和基本的方法使用:
Atomicinteger類中的方法列表:
| AtomicInteger()? ??????????創建具有初始值?0?的新 AtomicInteger。 |
| AtomicInteger(int?initialValue)? ??????????創建具有給定初始值的新 AtomicInteger。 |
| 方法摘要 | |
| ?int | addAndGet(int?delta)? ??????????以原子方式將給定值與當前值相加。 |
| ?boolean | compareAndSet(int?expect, int?update)? ??????????如果當前值?==?預期值,則以原子方式將該值設置為給定的更新值。 |
| ?int | decrementAndGet()? ??????????以原子方式將當前值減 1。 |
| ?double | doubleValue()? ??????????以?double?形式返回指定的數值。 |
| ?float | floatValue()? ??????????以?float?形式返回指定的數值。 |
| ?int | get()? ??????????獲取當前值。 |
| ?int | getAndAdd(int?delta)? ??????????以原子方式將給定值與當前值相加。 |
| ?int | getAndDecrement()? ??????????以原子方式將當前值減 1。 |
| ?int | getAndIncrement()? ??????????以原子方式將當前值加 1。 |
| ?int | getAndSet(int?newValue)? ??????????以原子方式設置為給定值,并返回舊值。 |
| ?int | incrementAndGet()? ??????????以原子方式將當前值加 1。 |
| ?int | intValue()? ??????????以?int?形式返回指定的數值。 |
| ?void | lazySet(int?newValue)? ??????????最后設置為給定值。 |
| ?long | longValue()? ??????????以?long?形式返回指定的數值。 |
| ?void | set(int?newValue)? ??????????設置為給定值。 |
| ?String | toString()? ??????????返回當前值的字符串表示形式。 |
| ?boolean | weakCompareAndSet(int?expect, int?update)? ??????????如果當前值?==?預期值,則以原子方式將該設置為給定的更新值。 |
| byteValue,?shortValue |
| clone,?equals,?finalize,?getClass,?hashCode,?notify,?notifyAll,?wait,?wait,?wait |
AtomicInteger源碼:
/** ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************//******* Written by Doug Lea with assistance from members of JCP JSR-166* Expert Group and released to the public domain, as explained at* http://creativecommons.org/publicdomain/zero/1.0/*/package java.util.concurrent.atomic; import sun.misc.Unsafe;/*** An {@code int} value that may be updated atomically. See the* {@link java.util.concurrent.atomic} package specification for* description of the properties of atomic variables. An* {@code AtomicInteger} is used in applications such as atomically* incremented counters, and cannot be used as a replacement for an* {@link java.lang.Integer}. However, this class does extend* {@code Number} to allow uniform access by tools and utilities that* deal with numerically-based classes.** @since 1.5* @author Doug Lea */ public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*** Creates a new AtomicInteger with the given initial value.** @param initialValue the initial value*/public AtomicInteger(int initialValue) {value = initialValue;}/*** Creates a new AtomicInteger with initial value {@code 0}.*/public AtomicInteger() {}/*** Gets the current value.** @return the current value*/public final int get() {return value;}/*** Sets to the given value.** @param newValue the new value*/public final void set(int newValue) {value = newValue;}/*** Eventually sets to the given value.** @param newValue the new value* @since 1.6*/public final void lazySet(int newValue) {unsafe.putOrderedInt(this, valueOffset, newValue);}/*** Atomically sets to the given value and returns the old value.** @param newValue the new value* @return the previous value*/public final int getAndSet(int newValue) {for (;;) {int current = get();if (compareAndSet(current, newValue))return current;}}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** @param expect the expected value* @param update the new value* @return true if successful. False return indicates that* the actual value was not equal to the expected value.*/public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** <p>May <a href="package-summary.html#Spurious">fail spuriously</a>* and does not provide ordering guarantees, so is only rarely an* appropriate alternative to {@code compareAndSet}.** @param expect the expected value* @param update the new value* @return true if successful.*/public final boolean weakCompareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}/*** Atomically increments by one the current value.** @return the previous value*/public final int getAndIncrement() {for (;;) {int current = get();int next = current + 1;if (compareAndSet(current, next))return current;}}/*** Atomically decrements by one the current value.** @return the previous value*/public final int getAndDecrement() {for (;;) {int current = get();int next = current - 1;if (compareAndSet(current, next))return current;}}/*** Atomically adds the given value to the current value.** @param delta the value to add* @return the previous value*/public final int getAndAdd(int delta) {for (;;) {int current = get();int next = current + delta;if (compareAndSet(current, next))return current;}}/*** Atomically increments by one the current value.** @return the updated value*/public final int incrementAndGet() {for (;;) {int current = get();int next = current + 1;if (compareAndSet(current, next))return next;}}/*** Atomically decrements by one the current value.** @return the updated value*/public final int decrementAndGet() {for (;;) {int current = get();int next = current - 1;if (compareAndSet(current, next))return next;}}/*** Atomically adds the given value to the current value.** @param delta the value to add* @return the updated value*/public final int addAndGet(int delta) {for (;;) {int current = get();int next = current + delta;if (compareAndSet(current, next))return next;}}/*** Returns the String representation of the current value.* @return the String representation of the current value.*/public String toString() {return Integer.toString(get());}public int intValue() {return get();}public long longValue() {return (long)get();}public float floatValue() {return (float)get();}public double doubleValue() {return (double)get();}} AtomicInteger其中的屬性:
private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;unsafe :java中的sun.misc.Unsafe包,提供了安全訪問內存的方法。這些方法提供給java訪問底層的JNI(java-native-interface),因為這些方法最終是調用c/c++實現。
valueOffset:指向相對于對象起始位置的偏移量(內存中)可以理解為引用指向的內存,通過這個值可以去內存中查找某個引用在內存的值。
value:引用的當前值[預期值E]
方法示例:
public class AtomTest {private static AtomicInteger num = new AtomicInteger(0);public static void main(String[] args) {System.out.println(num.compareAndSet(0, 1));//比較并設置,用0與內存中的值比較,相等的話,修改值為1System.out.println(num.compareAndSet(0, 1));//比較并設置,用0與內存中的值比較,相等的話,修改值為1System.out.println(num.get());;//獲取初值num.set(2);//設置初值,System.out.println(num.get());System.out.println(num.decrementAndGet());//獲取值自減返回減1之后的值System.out.println(num.addAndGet(2));//獲取值添加2然后返回添加后的值System.out.println(num.getAndIncrement());//獲取值并且自增,返回的是自增前的值System.out.println(num.getAndAdd(5));System.out.println(num.getAndDecrement());System.out.println(num.getAndSet(100));System.out.println(num.get());} }運行結果:
true false 1 2 1 3 3 4 9 8 100初始化的時候賦值為0,調用從compareAndSwap(0,1)之后返回true,compareAndSwap比較并交換,比較結果相同則修改值并返回TRUE不通則返回FALSE。
看看這個方法的源碼:
/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** @param expect the expected value* @param update the new value* @return true if successful. False return indicates that* the actual value was not equal to the expected value.*/public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}compareAndSwap:當前引用值和與要更新的值以及對象,和偏移量做參數去更新內存,根據對象和偏移量可以找到引用的內存值與引用值(期望值)作比較,相等則說明這個值在此對象獲得后未被修改,那么我們就可以更新,則結果為true。這個方法就是傳說中的CAS,CAS相較于synchonrized提供了一種無鎖的線程安全保證。
示例中的前兩個操作是一樣的,我們可以理解為兩個線程同時更新值為1,前一個快一點,發現更新的時候內存值未變則更新,等到第二個更新的時候原始值0與內存值(此時內存值變為1了)比較則失敗返回FALSE并且不進行更新。這樣就保證了一致性,而我們看到變量的值value使用voliate修飾的,保證了數據的內存可見性(一個線程修改其他線程可見)。所以多個線程并發的時候這個類代替Integer能夠保證安全。
這個操作非常像數據庫的樂觀鎖,給每個表添加一個version版本號,修改數據后要持久化先查詢看版本號一致不,一致的話則持久化,不一致則重新獲取值進行修改。
三、AtomicLong源碼以及與AtomicInteger的不同:
package java.util.concurrent.atomic; import sun.misc.Unsafe;/*** A {@code long} value that may be updated atomically. See the* {@link java.util.concurrent.atomic} package specification for* description of the properties of atomic variables. An* {@code AtomicLong} is used in applications such as atomically* incremented sequence numbers, and cannot be used as a replacement* for a {@link java.lang.Long}. However, this class does extend* {@code Number} to allow uniform access by tools and utilities that* deal with numerically-based classes.** @since 1.5* @author Doug Lea*/ public class AtomicLong extends Number implements java.io.Serializable {private static final long serialVersionUID = 1927816293512124184L;// setup to use Unsafe.compareAndSwapLong for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;/*** Records whether the underlying JVM supports lockless* compareAndSwap for longs. While the Unsafe.compareAndSwapLong* method works in either case, some constructions should be* handled at Java level to avoid locking user-visible locks.*/static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();/*** Returns whether underlying JVM supports lockless CompareAndSet* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.*/private static native boolean VMSupportsCS8();static {try {valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile long value;/*** Creates a new AtomicLong with the given initial value.** @param initialValue the initial value*/public AtomicLong(long initialValue) {value = initialValue;}/*** Creates a new AtomicLong with initial value {@code 0}.*/public AtomicLong() {}/*** Gets the current value.** @return the current value*/public final long get() {return value;}/*** Sets to the given value.** @param newValue the new value*/public final void set(long newValue) {value = newValue;}/*** Eventually sets to the given value.** @param newValue the new value* @since 1.6*/public final void lazySet(long newValue) {unsafe.putOrderedLong(this, valueOffset, newValue);}/*** Atomically sets to the given value and returns the old value.** @param newValue the new value* @return the previous value*/public final long getAndSet(long newValue) {while (true) {long current = get();if (compareAndSet(current, newValue))return current;}}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** @param expect the expected value* @param update the new value* @return true if successful. False return indicates that* the actual value was not equal to the expected value.*/public final boolean compareAndSet(long expect, long update) {return unsafe.compareAndSwapLong(this, valueOffset, expect, update);}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** <p>May <a href="package-summary.html#Spurious">fail spuriously</a>* and does not provide ordering guarantees, so is only rarely an* appropriate alternative to {@code compareAndSet}.** @param expect the expected value* @param update the new value* @return true if successful.*/public final boolean weakCompareAndSet(long expect, long update) {return unsafe.compareAndSwapLong(this, valueOffset, expect, update);}/*** Atomically increments by one the current value.** @return the previous value*/public final long getAndIncrement() {while (true) {long current = get();long next = current + 1;if (compareAndSet(current, next))return current;}}/*** Atomically decrements by one the current value.** @return the previous value*/public final long getAndDecrement() {while (true) {long current = get();long next = current - 1;if (compareAndSet(current, next))return current;}}/*** Atomically adds the given value to the current value.** @param delta the value to add* @return the previous value*/public final long getAndAdd(long delta) {while (true) {long current = get();long next = current + delta;if (compareAndSet(current, next))return current;}}/*** Atomically increments by one the current value.** @return the updated value*/public final long incrementAndGet() {for (;;) {long current = get();long next = current + 1;if (compareAndSet(current, next))return next;}}/*** Atomically decrements by one the current value.** @return the updated value*/public final long decrementAndGet() {for (;;) {long current = get();long next = current - 1;if (compareAndSet(current, next))return next;}}/*** Atomically adds the given value to the current value.** @param delta the value to add* @return the updated value*/public final long addAndGet(long delta) {for (;;) {long current = get();long next = current + delta;if (compareAndSet(current, next))return next;}}/*** Returns the String representation of the current value.* @return the String representation of the current value.*/public String toString() {return Long.toString(get());}public int intValue() {return (int)get();}public long longValue() {return get();}public float floatValue() {return (float)get();}public double doubleValue() {return (double)get();}} AtomicLong源碼關于AtomicLong的用法和AtomicInteger類似:
不同之處在于多了下面一部分:一個靜態的Boolean值VM_SUPPORTS_LONG_CAS,調用一個 native方法VMSupportCS8()返回虛擬機是否支持Long類型的無鎖CAS機制
/*** Records whether the underlying JVM supports lockless* compareAndSwap for longs. While the Unsafe.compareAndSwapLong* method works in either case, some constructions should be* handled at Java level to avoid locking user-visible locks.*/static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();/*** Returns whether underlying JVM supports lockless CompareAndSet* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.*/private static native boolean VMSupportsCS8();從這里可以看出不同的VM支持的數據類型可能有所差別,因為CAS需要硬件系統的支持。
四、AtomicReference源碼及使用:
/*** An object reference that may be updated atomically. See the {@link* java.util.concurrent.atomic} package specification for description* of the properties of atomic variables.* @since 1.5* @author Doug Lea* @param <V> The type of object referred to by this reference*/ public class AtomicReference<V> implements java.io.Serializable {private static final long serialVersionUID = -1848883965231344442L;private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile V value;/*** Creates a new AtomicReference with the given initial value.** @param initialValue the initial value*/public AtomicReference(V initialValue) {value = initialValue;}/*** Creates a new AtomicReference with null initial value.*/public AtomicReference() {}/*** Gets the current value.** @return the current value*/public final V get() {return value;}/*** Sets to the given value.** @param newValue the new value*/public final void set(V newValue) {value = newValue;}/*** Eventually sets to the given value.** @param newValue the new value* @since 1.6*/public final void lazySet(V newValue) {unsafe.putOrderedObject(this, valueOffset, newValue);}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.* @param expect the expected value* @param update the new value* @return true if successful. False return indicates that* the actual value was not equal to the expected value.*/public final boolean compareAndSet(V expect, V update) {return unsafe.compareAndSwapObject(this, valueOffset, expect, update);}/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** <p>May <a href="package-summary.html#Spurious">fail spuriously</a>* and does not provide ordering guarantees, so is only rarely an* appropriate alternative to {@code compareAndSet}.** @param expect the expected value* @param update the new value* @return true if successful.*/public final boolean weakCompareAndSet(V expect, V update) {return unsafe.compareAndSwapObject(this, valueOffset, expect, update);}/*** Atomically sets to the given value and returns the old value.** @param newValue the new value* @return the previous value*/public final V getAndSet(V newValue) {while (true) {V x = get();if (compareAndSet(x, newValue))return x;}}/*** Returns the String representation of the current value.* @return the String representation of the current value.*/public String toString() {return String.valueOf(get());}} AtomicReference源碼除了類型是個對象的之外,方法使用和AtomicInteger一模一樣:
AtomicReference的使用:
import java.util.concurrent.atomic.AtomicReference;public class AtomTest {private static AtomicReference<Pig> pigtest;public static void main(String[] args) {Pig pig = new Pig("豬堅強", 2);Pig pig2 = new Pig("豬八戒", 2);System.out.println("pig_hashCode:"+pig.hashCode());System.out.println("pig2_hashCode:"+pig2.hashCode());AtomTest.pigtest = new AtomicReference<Pig>(pig);System.out.println(pigtest.get().toString());System.out.println(pigtest.get().hashCode());System.out.println(pigtest.compareAndSet(pig, pig2));System.out.println(pigtest.compareAndSet(pig, pig2));System.out.println(pigtest.get().toString());System.out.println(pigtest.get().hashCode());} }運行結果:
pig_hashCode:779824645 pig2_hashCode:420110874 [豬堅強,2] 779824645 true false [豬八戒,2] 420110874第一步:先獲取pigTest的toString(),和hashCode,結果是【豬堅強,2】,hashCode:779824645【我們發現hashCode居然==pig_hashCode】
第二步:進行CAS修改為pig2結果為true,再進行一次結果為FALSE,
第三步:獲取pigTest的toString(),和hashCode,結果是【豬八戒,2】,hashCode:420110874【我們發現hashCode居然==pig2_hashCode】
結果說明了:pigtest是一個指向對象引用的引用,利用CAS操作可以修改pigTest指向的對象引用從而改變自身指向的對象。第一次CAS成功將pigtest指向的pig修改成了pig2.第二次CAS操作失敗了,可以保證多線程并發時的安全問題。
五、總結:
Atomic包下內容并不復雜,一句話來說就是提供了CAS無鎖的安全訪問機制。表現出來的是通過期望值E與內存值M作比較,相同則修改內存值M為更新值U。四個參數:當前對象this,偏移量V,期望值E,更新值U。
利用CAS+voliate+native的機制保證數據操作的原子性,可見性和一致性。voliate使變量可見,CAS調用unsafe中的native方法訪問系統底層的實現。unsafe中的這些方法直接操作內存,運用不當可能造成很大的問題。
其實從Atomic包中的原子類的探索中,只是想引出CAS這個概念,CAS同樣提供了一種線程安全的機制,而它不同于Synchonrized,synchonrized被稱之為重量級鎖,原因是因為粒度太強,加鎖就代表著線程阻塞,高并發訪問時帶來的性能問題是硬傷。
為了解決這種問題出現了兩種機制:一種就是CAS,另一種是鎖優化。
CAS是將阻塞下降到了底層CPU上(純屬個人理解,因為看到有權威是說存在阻塞的,可能讓別的線程知道已經更改了數據并且更新失敗也是一種阻塞吧),語言層面訪問效率遠遠低于系統內部硬件上,盡管同樣是阻塞,在系統內部加鎖解鎖的效率要高很多。但是需要的是硬件支持,不過現在絕大部分CPU都已經支持CAS了。
unsafe類:http://www.cnblogs.com/mickole/articles/3757278.html大家可以看這篇博客。
轉載于:https://www.cnblogs.com/NextNight/p/6600343.html
總結
以上是生活随笔為你收集整理的[Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在国内下载Eclipse及其插件
- 下一篇: java美元兑换,(Java实现) 美元