자바 에서 CAS 가 나타 난 원인 및 원리 분석
프롤로그
해결 방안
AtomicInteger 소스 코드 분석
총화
머리말
CAS:즉,compare and swap(비교 및 교체)입 니 다.CAS 는 다 중 스 레 드 병발 시 스 레 드 간 전환 시간 편 으로 인 한 원자 문 제 를 해결 해 야 합 니 다.
코드 부터 볼 게 요.
public class CasDemo1 {
static int k = 0;
public static void main(String[] args) {
for(int i = 0;i<10;i++) {
Thread t = new Thread(() -> {
// count 100
try {
//
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int j = 0; j < 100; j++) {
k++;
}
});
t.start();
}
try {
// 2 ,
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(k);
}
}
10 개의 스 레 드 를 동시에 k 의 값+100 으로 만 들 지만 결과 출력 값 은 1000 보다 작 습 니 다.왜 일 까요?이 유 는 k++이 조작 이 CPU 차원 에서 원자 성 을 보장 하지 않 고 분 리 될 수 있 기 때문이다.
1.조회 k 의 값 2,k=k+1
이 때 스 레 드 간 에 시간 편 전환 이 존재 하기 때문에 만약 에 스 레 드 A 가 첫 번 째 단계 까지 실행 하면 k 의 값=0 을 조회 합 니 다.이때 CPU 가 전환 되 었 고 스 레 드 B 는 1 과 2 를 성공 적 으로 실 행 했 습 니 다.이때 스 레 드 B 에 게 K=1 은 시간 편 이 A 스 레 드 로 전환 되 었 습 니 다.A 스 레 드 의 k=0 은 이때 2,k+1=1 을 실 행 했 습 니 다.그러면 우리 의 기대 와 다 르 고 병발 문제 가 발생 했 습 니 다.
해결 방안
상기 문 제 를 해결 하기 위해 서 우 리 는 자 물 쇠 를 추가 하여 병발 을 피 할 수 있 고 synchronized 를 사용 하여 자 물 쇠 를 추가 할 수 있 지만 synchronized 는 비관 적 인 자물쇠 사상 으로 성능 이 비교적 떨 어 질 것 이다.
CAS 가 채택 한 것 은 바로 낙관적 인 자물쇠 사상 이다.즉,집행 할 때 병발 문제 가 없다 고 가정 하고 먼저 비교 한 결과 변경 되 지 않 으 면 교체 되 고 변경 되면 상기 1 과 2 절 차 를 성공 할 때 까지 다시 집행 하 는 것 이다.
자바 는 이미 여러 가지 지원 과 병행 하 는 카 스 관련 종 류 를 제공 하 였 으 며,주로 자바.util.concurrent.atomic 패키지 에서,예 를 들 어 AtomicInteger,AtomicBoolean,AtomicLong 등 입 니 다.
AtomicInteger 소스 코드 분석
우 리 는 AtomicInteger 소스 코드 의 실현 을 보 았 다.
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
/**
* Gets the current value.
*
* @return the current value
*/
public final int get() {
return value;
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
......
}
Unsafe
Unsafe 클래스,전체 이름 은 sun.misc.Unsafe 입 니 다.이름 에서 우 리 는 이 클래스 가 일반 프로그래머 에 게'위험'이라는 것 을 알 수 있 습 니 다.일반 응용 개발 자 들 은 이런 종 류 를 사용 하지 않 습 니 다.만약 에 우리 가 Unsafe 류 를 기반 으로 하 는 기능 을 실현 해 야 한다 면 반사 로 Unsafe 류 를 가 져 올 수 밖 에 없습니다.Unsafe 는 생 성 할 때 제한 을 가 했 기 때문에 rt.jar 가방 에 있 는 클래스 만 접근 할 수 있 습 니 다.Unsafe 의 getUnsafe 에서 알 수 있 습 니 다.
Unsafe 는 자바 에서 메모 리 를 직접 조작 하 는 능력 을 제공 합 니 다.
valueOffset
value Offset=unsafe.object FieldOffset(AtomicInteger.class.getDeclared Field("value"))이 코드 를 보면 value Offset 의 값 은 AtomicInteger 의 value 값 이 메모리 에 있 는 주소,즉 오프셋 임 을 알 수 있 습 니 다.
compareAndSwapInt
unsafe.compareAndSwapInt(this, valueOffset, expect, update)
카 스 의 핵심 작업,즉 조회 매개 변수 1 의 메모리 주 소 는 value Offset 의 값 입 니 다.매개 변수 3 과 같 을 때 매개 변수 4 로 수정 하고 성공 을 되 돌려 줍 니 다.같 지 않 을 때 false 매개 변수 1 을 되 돌려 줍 니 다.작업 의 인 스 턴 스 매개 변수 2:작업 인 스 턴 스 중 메모리 주소 매개 변수 3:예상 값 매개 변수 4:변경 되 기 를 원 하 는 값
incrementAndGet
늘다
getAndAddInt 방법 보기
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
// valueOffset
var5 = this.getIntVolatile(var1, var2);
// cas , var5 var5 var5+var4
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
즉,최종 적 으로 AtomicInteger 의 value+1 을+1 후의 값 으로 되 돌려 줍 니 다.
총결산
AtomicInteger 의 소스 코드 를 보고 우 리 는 기본적으로 카 스 의 실현 을 알 게 되 었 습 니 다.즉,Unsafe 류 를 통 해 메모리 에 있 는 값 을 직접 비교 하고 같 으 면 교체 하 며 실 패 는 성공 할 때 까지 자전 합 니 다.메모리 에 있 는 값 을 직접 비교 하여 상기 시간 대 전환 으로 인 한 원자 문 제 를 해결 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.