동기 데이터 구조의 원자 복합 류
머리말
앞에서 소개 한 원자 업데이트 기 는 모두 하나의 대상 이나 필드 요 소 를 대상 으로 원자 업데이트 작업 을 할 뿐 입 니 다. 제1장 에서 언급 한 네 번 째 복합 형 원자 업데이트 기 는 하나의 인용 변 수 를 다른 변수 와 연결 시 켜 복합 적 인 원자 업데이트 작업 을 실현 할 수 있 습 니 다. 이런 업데이트 기 는 두 가지 가 있 습 니 다. Atomic MarkableReference, Atomic Stamped Reference 입 니 다.
AtomicStampedReference
Atomic Stamped Reference 는 CAS 작업 과정 에서 의 ABA 문 제 를 해결 하기 위해 int 형 표지 버 전 번호 와 유사 한 변 수 를 이원 조합 전체 로 인용 하기 때문에 Atomic Stamped Reference 는 버 전 스탬프 가 있 는 원자 인용 유형 이 라 고도 부른다.인용 형식 을 원자 업데이트 하려 고 할 때마다 최소한 가지 고 있 는 버 전 번 호 를 비교 해 야 합 니 다. 버 전 번호 가 일치 하지 않 으 면 업데이트 에 실 패 했 습 니 다. 물론 업데이트 할 때 해당 하 는 버 전 번호 도 함께 업 데 이 트 됩 니 다.소스 코드 로 분석 을 시작 하 는 게 좋 을 것 같 습 니 다.
public class AtomicStampedReference {
// Pair stamp
private static class Pair {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static Pair of(T reference, int stamp) {
return new Pair(reference, stamp);
}
}
// pair volatile
private volatile Pair pair;
// ,
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
....
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset =
objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
// pair
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
}
이상 의 소스 코드 를 통 해 알 수 있 듯 이 AtomicStamped Reference 내부 에 정적 내부 클래스 Pair 의 인 스 턴 스 변수 pair 가 있 습 니 다. AtomicStamped Reference 를 초기 화 할 때 들 어 오 는 초기 참조 변수 와 초기 버 전 번 호 를 저장 합 니 다. volatile 에 의 해 수 정 된 것 이 므 로 가시 성 을 확보 합 니 다.또한 원자 업데이트 작업 을 할 때마다 오래된 pair 대신 새로운 pair 인 스 턴 스 를 생 성 합 니 다. 즉, 진정한 인용 변수 와 버 전 번 호 를 하나의 전체 로 업데이트 하기 때문에 Atomic Stamped Reference 내부 에서 이 pair 변수의 오프셋 주 소 를 미리 가 져 와 원자 업데이트 작업 을 준비 합 니 다.
다음은 그 방법 을 보 자.그것 의 방법 은 두 가지 로 나 뉘 는데 하 나 는 get 방법 이 고 다른 하 나 는 원자 업데이트 방법 이다.
//
public V getReference() {
return pair.reference;
}
//
public int getStamp() {
return pair.stamp;
}
// , int ,
// int , 。
// 。
public V get(int[] stampHolder) {
Pair pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
그 다음 에 가장 중요 한 원자 업데이트 작업 과 관련 된 방법 입 니 다.
// , 。 true
// , , happen-before 。
// compareAndSet, JVM 。
public boolean weakCompareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
return compareAndSet(expectedReference, newReference,
expectedStamp, newStamp);
}
//CAS , , volatile pair ,
, 。 true
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
// 。
public void set(V newReference, int newStamp) {
Pair current = pair;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
}
// , 。 , , true
public boolean attemptStamp(V expectedReference, int newStamp) {
Pair current = pair;
return
expectedReference == current.reference &&
(newStamp == current.stamp ||
casPair(current, Pair.of(expectedReference, newStamp)));
}
// CAS , unsafe CAS pair 。 true
private boolean casPair(Pair cmp, Pair val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
상기 원자 업데이트 방법 을 통 해 알 수 있 듯 이 AtomicStamped Reference 는 Unsafe 의 CAS 방법 + Volatile 키 워드 를 이용 하여 실제 인용 변수 와 int 의 버 전 번 호 를 저장 하 는 Pair 인 스 턴 스 를 업데이트 합 니 다.
AtomicMarkableReference
AtomicMarkableReference 는 사실 AtomicStamped Reference 의 특례 로 볼 수 있 습 니 다. AtomicMarkableReference 는 하나의 인용 변수 와 하나의 불 변 수 를 하나의 이원 으로 조합 하 는 것 이기 때문에 버 전 번 호 는 true 와 false 만 있 는 것 과 같 습 니 다. AtomicStamped Reference 처럼 모든 업데이트 에 버 전 번 호 를 기록 할 수 있 습 니 다.어떤 경우 에 우 리 는 우리 가 주목 하 는 대상 이 변경 되 었 는 지 알 아야 하기 때문에 변경 되 었 으 면 더 이상 변경 하지 않 습 니 다. 예 를 들 어 노드 에 삭 제 된 표 시 는 Atomic Markable Reference 를 통 해 우리 의 요구 에 도달 할 수 있 습 니 다.
Atomic MarkableReference 의 소스 코드 에 대해 서 는 Atomic Stamped Reference 의 디자인 원리 와 같 습 니 다. 표지 버 전의 int 형 변 수 를 불 형의 변수 로 바 꾸 었 을 뿐 정적 내부 클래스 Pair 로 이 인용 변 수 를 불 변수 와 조합 하여 원자 업 데 이 트 를 진행 하 였 습 니 다.그래서 그 소스 코드 는 더 이상 일일이 열거 하지 않 는 다.
public class AtomicMarkableReferenceTest {
public static void main(String[] args) {
AtomicMarkableReference amr = new AtomicMarkableReference("ABC", false);
boolean result = amr.attemptMark("ABC", true);// true
System.out.println(result);
System.out.println(amr.isMarked());// ,true
AtomicStampedReference asr = new AtomicStampedReference("123", 0);
boolean seted = asr.compareAndSet("123", "456", 0, 1);//
System.out.println(seted);
System.out.println(asr.getStamp());// 1
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.