AtomicInteger原始碼解析
此文已由作者趙計剛授權網易雲社群釋出。
歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。
1、原子類
可以實現一些原子操作
基於CAS
下面就以AtomicInteger為例。
2、AtomicInteger
在沒有AtomicInteger之前,對於一個Integer的執行緒安全操作,是需要使用同步鎖來實現的,當然現在也可以通過ReentrantLock來實現,但是最好最方便的實現方式是採用AtomicInteger。
具體示例:
package com.collection.test; import java.util.concurrent.atomic.AtomicInteger; /** * 原子類的測試 */ public class AtomicTest { private static AtomicInteger atomicInteger = new AtomicInteger(); //獲取當前值 public static void getCurrentValue(){ System.out.println(atomicInteger.get());//-->0 } //設定value值 public static void setValue(){ atomicInteger.set(12);//直接用12覆蓋舊值 System.out.println(atomicInteger.get());//-->12 } //根據方法名稱getAndSet就知道先get,則最後返回的就是舊值,如果get在後,就是返回新值 public static void getAndSet(){ System.out.println(atomicInteger.getAndSet(15));//-->12 } public static void getAndIncrement(){ System.out.println(atomicInteger.getAndIncrement());//-->15 } public static void getAndDecrement(){ System.out.println(atomicInteger.getAndDecrement());//-->16 } public static void getAndAdd(){ System.out.println(atomicInteger.getAndAdd(10));//-->15 } public static void incrementAndGet(){ System.out.println(atomicInteger.incrementAndGet());//-->26 } public static void decrementAndGet(){ System.out.println(atomicInteger.decrementAndGet());//-->25 } public static void addAndGet(){ System.out.println(atomicInteger.addAndGet(20));//-->45 } public static void main(String[] args) { AtomicTest test = new AtomicTest(); test.getCurrentValue(); test.setValue(); //返回舊值系列 test.getAndSet(); test.getAndIncrement(); test.getAndDecrement(); test.getAndAdd(); //返回新值系列 test.incrementAndGet(); test.decrementAndGet(); test.addAndGet(); } }
原始碼:
private volatile int value;// 初始化值 /** * 建立一個AtomicInteger,初始值value為initialValue */ public AtomicInteger(int initialValue) { value = initialValue; } /** * 建立一個AtomicInteger,初始值value為0 */ public AtomicInteger() { } /** * 返回value */ public final int get() { return value; } /** * 為value設值(基於value),而其他操作是基於舊值<--get() */ public final void set(int newValue) { value = newValue; } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** * 基於CAS為舊值設定新值,採用無限迴圈,直到設定成功為止 * * @return 返回舊值 */ public final int getAndSet(int newValue) { for (;;) { int current = get();// 獲取當前值(舊值) if (compareAndSet(current, newValue))// CAS新值替代舊值 return current;// 返回舊值 } } /** * 當前值+1,採用無限迴圈,直到+1成功為止 * @return the previous value 返回舊值 */ public final int getAndIncrement() { for (;;) { int current = get();//獲取當前值 int next = current + 1;//當前值+1 if (compareAndSet(current, next))//基於CAS賦值 return current; } } /** * 當前值-1,採用無限迴圈,直到-1成功為止 * @return the previous value 返回舊值 */ public final int getAndDecrement() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return current; } } /** * 當前值+delta,採用無限迴圈,直到+delta成功為止 * @return the previous value 返回舊值 */ public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } } /** * 當前值+1, 採用無限迴圈,直到+1成功為止 * @return the updated value 返回新值 */ public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 當前值-1, 採用無限迴圈,直到-1成功為止 * @return the updated value 返回新值 */ public final int decrementAndGet() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 當前值+delta,採用無限迴圈,直到+delta成功為止 * @return the updated value 返回新值 */ public final int addAndGet(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return next;//返回新值 } } /** * 獲取當前值 */ public int intValue() { return get(); }
說明:使用與原始碼都簡單到爆了!自己看看註釋。
注意:
value是volatile的,關於volatile的相關內容見《附2 volatile》,具體連結:http://www.cnblogs.com/java-zhao/p/5125698.html
單步操作:例如set()是直接對value進行操作的,不需要CAS,因為單步操作就是原子操作。
多步操作:例如getAndSet(int newValue)是兩步操作-->先獲取值,在設定值,所以需要原子化,這裡採用CAS實現。
對於方法是返回舊值還是新值,直接看方法是以get開頭(返回舊值)還是get結尾(返回新值)就好
CAS:比較CPU記憶體上的值是不是當前值current,如果是就換成新值update,如果不是,說明獲取值之後到設定值之前,該值已經被別人先一步設定過了,此時如果自己再設定值的話,需要在別人修改後的值的基礎上去操作,否則就會覆蓋別人的修改,所以這個時候會直接返回false,再進行無限迴圈,重新獲取當前值,然後再基於CAS進行加減操作。
如果還是不懂CAS,類比資料庫的樂觀鎖。
補充一個東西:
1 // setup to use Unsafe.compareAndSwapInt for updates 2 private static final Unsafe unsafe = Unsafe.getUnsafe(); 3 private static final long valueOffset; 4 5 static { 6 try { 7 valueOffset = unsafe.objectFieldOffset 8 (AtomicInteger.class.getDeclaredField("value")); 9 } catch (Exception ex) { throw new Error(ex); } 10 } 11 12 private volatile int value;
這是AtomicInteger的所有屬性,其中value存的是當前值,而當前值存放的記憶體地址可以通過valueOffset來確定。實際上是“value欄位相對Java物件的起始地址的偏移量”
1 public final boolean compareAndSet(int expect, int update) { 2 return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 3 }
CAS方法:通過對比“valueOffset上的value”與expect是否相同,來決定是否修改value值為update值。
免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐
更多網易技術、產品、運營經驗分享請點選。
相關文章:
【推薦】 Android中Textview顯示Html,圖文混排,支援圖片點選放大
【推薦】 結合jenkins以及PTP平臺的效能迴歸測試
【推薦】 視覺設計師的進化