今天繼續探索j.u.c中的12個原子操作Atomic,可以進行分為四組。基本類型、數組類型、引用類型、屬性類型。這些類都是採用Unsafe中的方法進行實現。
基本類型
Atomic提供以下幾個類
- AtomicBoolean
- AtomicLong
- AtomicInteger
它們的實現方法都類似,採用Unsafe實現,如AtomicInteger為例
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
上面代碼是根據類中‘‘value’’字段取內存地址,而value採用 volatile字段進行修飾
private volatile int value;
AtomicInteger主要方法
- get() //獲取值
- getAndIncrement() //當前值加1, 並返回 舊值
- getAndDecrement() //當前值減1,並返回 舊值
- incrementAndGet() //當前值加1並返回新值
- decrementAndGet() //當前值減1並返回新值
- compareAndSet(expect,update) //當前值為預期值時, 更新新值
面試題
- 請回答以下代碼的值分別是什麼 ?
public class AtomicIntegerDemo {
public static void main(String[] args) {
AtomicInteger atomic = new AtomicInteger();
System.out.println(atomic.getAndIncrement());
System.out.println(atomic.incrementAndGet());
atomic.lazySet(4);
System.out.println(atomic.compareAndSet(2,4));
System.out.println(atomic.get());
}
}
2.為什麼AtomicBoolean源碼中value為什麼是int類型?
數據類型
Atomic提供以下幾個類:
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
採用原子數組方式實現
private static final int shift;
private final int[] array;
static {
int scale = unsafe.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
AtomicIntegerArrary主要的方法:
- addAndGet //對指定下標的值進行兩值相加並返回
- compareAndSet //對指定下標的值,若為期待值時進行賦值返回 true
- get //返回指定下標的值
- getAndIncrement
- incrementAndGet
- getAndDecrement
- decrementAndGet
AtomicReferenceArray構造方法必須有參數,初始化組數長度。在每次操作時跟數組操作是一樣的,每次操作都要帶著下標去操作方法
AtomicReferenceArray<user> array = new AtomicReferenceArray<>(1);
/<user>
面試題
1.請回答以下代碼輸出結果是什麼?
public class AtomicIntegerArrayDemo {
public static void main(String[] args) {
int[] v =new int[]{1,2};
AtomicIntegerArray array = new AtomicIntegerArray(v);
System.out.println(array.addAndGet(0,3));
System.out.println(array.get(0));
System.out.println(array.compareAndSet(1,2,10));
System.out.println(array.get(1));
}
}
引用類型
Atomic提供以下幾個類
- AtomicReference //原子引用類型
- AtomicMarkableReference //帶有標記位的引用類型
- AtomicStampedReference //帶有版本號的引用類型
AtomicReference的實現方式與基本類型實現相同,但不同的是V是可變對象,而不像基本類型那樣是具體的基本類型。
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile V value;
AtomicMarkableReference是解決ABA的問題, 它不關心版本號,關心的是數據是否有變化
private static class Pair{
final T reference;
final boolean mark;
private Pair(T reference, boolean mark) {
this.reference = reference;
this.mark = mark;
}
staticPair of(T reference, boolean mark) {
return new Pair(reference, mark);
}
}
private volatile Pairpair;
AtomicStampedReference的實現與AtomicMarkableReference的實現類似。也是解決ABA問題,
private static class Pair{
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
staticPair of(T reference, int stamp) {
return new Pair(reference, stamp);
}
}
private volatile Pairpair;
屬性類型
Atomic提供以下幾個類
- AtomicIntegerFieldUpdater //整型字段更新器
- AtomicLongFieldUpdater //長整型字段更新器
- AtomicReferenceFieldUpdater //引用字段的更新器
AtomicIntegerFieldUpdater主要方法
- newUpdater
- incrementAndGet
- getAndIncrement
- getAndDecrement
- get
- getAndAdd
- getAndSet
- decrementAndGet
- lazySet
這些方法的原理跟上面的類都差不多,這裡就不加註釋了非常好理解。
AtomicIntegerFieldUpdater是個抽象類,不通過直接new對象,而需要使用靜態方法創建對象, 請看源碼
public abstract class AtomicIntegerFieldUpdater{
@CallerSensitive
public static AtomicIntegerFieldUpdater newUpdater(Class tclass,
String fieldName) {
return new AtomicIntegerFieldUpdaterImpl
(tclass, fieldName, Reflection.getCallerClass());
}
在newUpdater 方法以下幾個要求
- 第一個參數是個類類型
- 第二個參數是 更新的字段名
- 字段名必須是volatile int 進行修飾
示例代碼,順序請回答下結果
public class AtomicIntegerFieldUpdaterDemo {
public static void main(String[] args) {
AtomicIntegerFieldUpdater<user> updater =
AtomicIntegerFieldUpdater.newUpdater(User.class, "name");
System.out.println(updater.get(new User()));
System.out.println(updater.incrementAndGet(new User()));
System.out.println(updater.getAndIncrement(new User()));
}
static class User {
volatile int name;
}
}
/<user>
AtomicReferenceFieldUpdater 的常用方法
- newUpdater //
- get //獲取指定對象字段的值
- set //設置指定對象字段的值
- getAndAccumulate //通過指定對象的值與當前值進行計算,返回舊值
- getAndSet //設置指定對象字段的值,返回舊值
- getAndUpdate //1.8 計算 返回 舊值
- lazySet
示例代碼,並回答下執行結果
public class AtomicReferenceFieldUpdaterDemo {
public static void main(String[] args) {
AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(User.class,String.class
,"name");
User user = new User();
user.name = "hello";
System.out.println(updater.getAndAccumulate(user, "java",new BinaryOperator<string>() {
@Override
public String apply(String s, String s2) {
return s+" "+s2;
}
}));
System.out.println(updater.getAndUpdate(user,(x)->x+" word"));
System.out.println(user.name);
}
static class User{
volatile String name;
}
}
/<string>
以上是根據個人理解做了分析,如有不正確請留言討論。
----------------------------------------------------------
閱讀更多 零售雲技術內參 的文章