잠 금 없 는 병렬 정책 (비교 교환)
1. 잠 금 없 는 스 레 드 안전 정수 (AtomicInteger) 내부 실현 분석 (jdk 1.8 기반):
private volatile int value;
value AtomicInteger , volatile ,
private static final long valueOffset;
valueOffset value AtomicInteger , valueOffset AtomicInteger value , :
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
상용 방법 예:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
// 1, 1
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
// delta,
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
// 1,
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
delta, delta
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
(expect) , (update)
public float floatValue() {
return (float)get();
}
float
이러한 유형의 방법 은 대체적으로 unsafe 를 사용 하여 실현 되 고 unsafe 중의 방법 은 1 층 은 c 로 실현 된다. 예 를 들 어:
public native boolean compareAndSwapInt(Object obj, long offset,int expect,int update);
유사 한 실현 은 AtomicLong, AtomicBoolean, AtomicReference 도 있 습 니 다. 더 이상 언급 하지 않 겠 습 니 다.
2. 존재 하 는 문제점:
CAS 작업 을 사용 하면 현재 데이터 의 상 태 를 판단 할 수 없습니다. 어떤 스 레 드 가 value 를 수정 하면 다음 스 레 드 는 이전 스 레 드 가 수정 되 기 전의 값 을 수정 합 니 다. 그 후에 스 레 드 는 수정 되 었 는 지 모 릅 니 다.흔히 말 하 는 ABA 문제 다. 이러한 상황 에 대해 JDK 는 AtomicStamped Reference 류 를 제공 하고 내부 에서 대상 값 과 시간 스탬프 를 동시에 유지 합 니 다.Atomic Stamped Reference 대상 의 값 이 수정 되 었 을 때 대상 값 을 업데이트 하 는 것 외 에 시간 스탬프 를 동시에 업데이트 해 야 합 니 다.Atomic Stamped Reference 가 대상 값 을 설정 할 때 대상 값 과 시간 스탬프 는 모두 기대 치 를 만족 시 켜 야 기록 에 성공 할 수 있 습 니 다.따라서 대상 값 이 원래 값 으로 쓰 여 져 도 시간 스탬프 가 바 뀌 면 부적 절 한 기록 을 막 을 수 있다.
내부 실현 분석:
private volatile Pair pair;
pair 는 대상 값 과 시간 스탬프 를 저 장 했 습 니 다. Pair 류 소스 코드 는 다음 과 같 습 니 다.
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);
}
}
compare AndSet 방법 을 예 로 들 면:
/**
* Atomically sets the value of both the reference and stamp
* to the given update values if the
* current reference is {@code ==} to the expected reference
* and the current stamp is equal to the expected stamp.
*
* @param expectedReference the expected value of the reference
* @param newReference the new value for the reference
* @param expectedStamp the expected value of the stamp
* @param newStamp the new value for the stamp
* @return {@code true} if successful
*/
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)));
}
당기 기대 치 는 현재 값 과 같 고 기대 시간 스탬프 와 현재 시간 스탬프 가 같 을 때 만 새 값 을 기록 하고 시간 스탬프 를 동시에 업데이트 합 니 다. casPair 방법 은 다음 과 같 습 니 다.
private boolean casPair(Pair cmp, Pair val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
3. 안전 하지 않 은 클래스 (unsafe)
자바 는 운영 체제 의 밑바닥 에 직접 접근 할 수 없고 로 컬 방법 을 통 해 접근 할 수 있 습 니 다. 그 중에서 포인터 와 유사 한 조작 을 봉 인 했 습 니 다. unsafe 류 를 사용 하면 메모 리 를 분배 하고 메모 리 를 방출 할 수 있 습 니 다. 클래스 에서 3 개의 로 컬 방법 인 allocateMemory, reallocate Memory, freeMemory 는 각각 메모 리 를 분배 하 는 데 사 용 됩 니 다. 메모 리 를 확장 하고 메모리 unsafe 를 방출 하 는 주요 방법 은 다음 과 같 습 니 다.
// int
private native int getInt(Object o,long offset);
// int
private native int putInt(Object o,long offset,int x);
//
private native long objectFieldOffset(Field f);
// int , volatile
private native void putIntVolatile(Object o,long offset,int x);
// int , volatile
private native int getIntVolatile(Object o,long offset);
// putIntVolatile , volatile
private native void putOrderedInt(Object o,long offset,int x);
JDK 개발 자 들 은 이러한 종 류 를 사용 하 기 를 원 하지 않 습 니 다. unsafe 인 스 턴 스 를 얻 는 방법 은 공장 방법 getUnsafe () 를 호출 하 는 것 입 니 다. 이 를 실현 하 는 것 은 다음 과 같 습 니 다.
public static Unsafe(){
Class cc=Reflection.getCallerClass();
if(cc.getClassLoader()!=null)
throw new SecurityException("Unsafe");
return theUnsafe;
}
이 방법 을 호출 할 때 이 방법 을 호출 하 는 클래스 를 검사 합 니 다. 이 클래스 의 ClassLoader 가 null 이 아니라면 이상 을 던 지고 접근 을 거부 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.