概述:
AtomicReference和AtomicInteger非常類似,不同之處就在於AtomicInteger是對整數的封裝,底層採用的是compareAndSwapInt實現CAS,比較的是數值是否相等,而AtomicReference則對應普通的對象引用,底層使用的是compareAndSwapObject實現CAS,比較的是兩個對象的地址是否相等。也就是它可以保證你在修改對象引用時的線程安全性。
順便說一下:引用類型的賦值是原子的。雖然虛擬機規範中說64位操作可以不是原子性的,可以分爲兩個32位的原子操作,但是目前商用的虛擬機幾乎都實現了64位原子操作。
.AtomicReference.set(V newValue) 注意此方法是原子的。這個方法裏面就一句代碼,引用賦值本身它就是原子性的不會被cpu打斷的。
源碼如下:
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
// 獲取Unsafe對象,Unsafe的作用是提供CAS操作
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); }
}
// volatile類型
private volatile V value;
public AtomicReference(V initialValue) {
value = initialValue;
}
public AtomicReference() {
}
public final V get() {
return value;
}
public final void set(V newValue) {
value = newValue;
}
public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
}
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
public final boolean weakCompareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
public final V getAndSet(V newValue) {
while (true) {
V x = get();
if (compareAndSet(x, newValue))
return x;
}
}
public String toString() {
return String.valueOf(get());
}
}
public class Main{
public static void main(String[] args) {
// 創建兩個Person對象,它們的id分別是101和102。
Person2 p1 = new Person2(101);
Person2 p2 = new Person2(102);
// 新建AtomicReference對象,初始化它的值爲p1對象
AtomicReference ar = new AtomicReference(p1);
//更改p1的id.
p1.setId(106);
// 通過CAS設置ar。如果ar的值爲p1的話,則將其設置爲p2。
ar.compareAndSet(p1, p2);
Person2 p3 = (Person2)ar.get();
System.out.println("p3 is "+p3);
System.out.println("p3.equals(p1)="+p3.equals(p1));
}
}
class Person2 {
volatile long id;
public Person2(long id) {
this.id = id;
}
public String toString() {
return "id:"+id;
}
public void setId(long id){
this.id=id;
}
}
運行結果如下:
p3 is id:102
p3.equals(p1)=false
可以看出,修改了p1的id對compareAndSet()並沒有影響,因爲修改id僅僅改變了p1的成員變量,而AtomicReference底層使用的是compareAndSwapObject實現CAS,比較的是兩個對象的地址是否相等。也就是它可以保證你在修改對象引用時的線程安全性。上面代碼成功的將原子類中的引用從p1變成p2,而且是線程安全的。