Java concurrencyのAtomicReference原子類動力ノードJava学院の整理
3899 ワード
AtomicReference紹介と関数リスト
AtomicReferenceは「対象」に対して原子操作を行う役割をしています。
AtomicReference関数一覧
JDK 1.7.0_にあります40のAtomicReference.javaのソースコードは以下の通りです。
AtomicReferenceのソースコードは比較的簡単です。これは「volatile」と「Unsafeが提供するCAS関数によって実現される」原子操作です。
(01)valueはvolatileタイプです。これは、あるスレッドがvalueの値を修正すると、他のスレッドが見ているvalue値が最新のvalue値、すなわち修正後のvolatileの値となることを保証します。
(02)CASでvalueを設定する。これは保証されています。あるスレッド池がCAS関数(例えば、compreAndSet関数)によってvalueを設定すると、その動作は原子であり、つまりスレッドがvalueを操作している間は中断されません。
AtomicReferenceの例
//AtomicReferenceTest.javaのソースコード
AtomicReferenceオブジェクトarを新規作成するとp 1に初期化します。
続いて、CAS関数でそれを設定します。arの値がp 1ならp 2に設定します。
最後に、ar対応のオブジェクトを取得し、結果を印刷します。p 3.equals(p 1)の結果はfalseであり、これはPersonがequals()をカバーする方法ではなく、Object.javaから継承されるequals()方法を採用しているからである。Object.javaのequals()は、実際には「==」を呼び出して、2つのオブジェクトのアドレスが等しいかどうかを比較します。
AtomicReferenceは「対象」に対して原子操作を行う役割をしています。
AtomicReference関数一覧
// null AtomicReference。
AtomicReference()
// AtomicReference。
AtomicReference(V initialValue)
// == , 。
boolean compareAndSet(V expect, V update)
// 。
V get()
// , 。
V getAndSet(V newValue)
// 。
void lazySet(V newValue)
// 。
void set(V newValue)
// 。
String toString()
// == , 。
boolean weakCompareAndSet(V expect, V update)
AtomicReferenceソース分析(JDK 1.7.0_に基づく。40)JDK 1.7.0_にあります40のAtomicReference.javaのソースコードは以下の通りです。
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());
}
}
説明:AtomicReferenceのソースコードは比較的簡単です。これは「volatile」と「Unsafeが提供するCAS関数によって実現される」原子操作です。
(01)valueはvolatileタイプです。これは、あるスレッドがvalueの値を修正すると、他のスレッドが見ているvalue値が最新のvalue値、すなわち修正後のvolatileの値となることを保証します。
(02)CASでvalueを設定する。これは保証されています。あるスレッド池がCAS関数(例えば、compreAndSet関数)によってvalueを設定すると、その動作は原子であり、つまりスレッドがvalueを操作している間は中断されません。
AtomicReferenceの例
//AtomicReferenceTest.javaのソースコード
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
public static void main(String[] args){
// Person , id 101 102。
Person p1 = new Person(101);
Person p2 = new Person(102);
// AtomicReference , p1
AtomicReference ar = new AtomicReference(p1);
// CAS ar。 ar p1 , p2。
ar.compareAndSet(p1, p2);
Person p3 = (Person)ar.get();
System.out.println("p3 is "+p3);
System.out.println("p3.equals(p1)="+p3.equals(p1));
}
}
class Person {
volatile long id;
public Person(long id) {
this.id = id;
}
public String toString() {
return "id:"+id;
}
}
実行結果:
p3 is id:102
p3.equals(p1)=false
結果説明:AtomicReferenceオブジェクトarを新規作成するとp 1に初期化します。
続いて、CAS関数でそれを設定します。arの値がp 1ならp 2に設定します。
最後に、ar対応のオブジェクトを取得し、結果を印刷します。p 3.equals(p 1)の結果はfalseであり、これはPersonがequals()をカバーする方法ではなく、Object.javaから継承されるequals()方法を採用しているからである。Object.javaのequals()は、実際には「==」を呼び出して、2つのオブジェクトのアドレスが等しいかどうかを比較します。