자바 의 자물쇠(4):낙관적 자물쇠 의 실현 메커니즘-CAS 조작
6208 단어 병렬 프로 그래 밍낙관적 자물쇠cas
다음 내용 은 다음 과 같 습 니 다.http://www.hollischuang.com/archives/1537
스 레 드 보안
자바 는 다 중 스 레 드 로 알려 져 있다.그러나 자바 의 다 중 스 레 드 에 대한 지 지 는 양날 의 검 이다.여러 스 레 드 작업 이 자원 을 공유 하 는 상황 과 관련 되면 잘 처리 하지 못 하면 스 레 드 안전 문제 가 발생 할 수 있 습 니 다.스 레 드 안전성 은 매우 복잡 할 수 있 습 니 다.충분 한 동기 화 없 이 여러 스 레 드 의 작업 수행 순 서 는 예측 할 수 없습니다.
자바 에서 다 중 스 레 드 통신 을 하 는 주요 방식 은 메모 리 를 공유 하 는 방식 이다.공유 메모리 의 주요 관심 사 는 두 가지 가 있다.가시 성과 질서 성 이다.게다가 복합 작업 의 원자 성 을 더 하면 우 리 는 자바 의 스 레 드 안전성 문제 의 주요 관심 사 는 3 가지 가 있다 고 볼 수 있다.가시 성,질서 성과 원자 성 이다.
자바 메모리 모델(JMM)은 가시 적 이 고 질서 있 는 문 제 를 해 결 했 고 자 물 쇠 는 원자 적 인 문 제 를 해결 했다.JMM 및 자물쇠 에 관 한 다른 지식 은 자세히 소개 하지 않 겠 습 니 다.그러나 우 리 는 문 제 를 토론 해 야 한다.그것 이 바로 자물쇠 가 도대체 유리 하고 해 가 없 는 것 이 아니 냐 는 것 이다.
질문
자바 는 JDK 1.5 이전에 synchronized 키워드 로 동기 화 를 보장 합 니 다.이 는 일치 하 는 잠 금 프로 토 콜 을 사용 하여 공유 상태 에 대한 접근 을 조율 하고 어느 스 레 드 가 공유 변수의 자 물 쇠 를 가지 고 있 든 독점 적 인 방식 으로 이 변 수 를 방문 할 수 있 습 니 다.독점 자 물 쇠 는 사실 비관 적 인 자물쇠 이기 때문에 synchronized 는 비관 적 인 자물쇠 라 고 할 수 있다.
비관 적 잠 금 메커니즘 에는 다음 과 같은 문제 가 존재 한다.
다 중 스 레 드 경쟁 에서 자 물 쇠 를 추가 하고 자 물 쇠 를 방출 하면 비교적 많은 문맥 전환 과 스케줄 지연 을 초래 하여 성능 문 제 를 일 으 킬 수 있다.
하나의 스 레 드 가 자 물 쇠 를 가지 고 있 으 면 이 자 물 쇠 를 필요 로 하 는 다른 모든 스 레 드 가 걸 릴 수 있 습 니 다.
우선 순위 가 높 은 스 레 드 가 우선 순위 가 낮은 스 레 드 의 잠 금 을 기다 리 면 우선 순위 가 뒤 바 뀌 어 성능 위험 을 초래 할 수 있 습 니 다.
또 다른 효과 적 인 자 물 쇠 는 낙관 자물쇠 다.낙관 자물쇠 란 매번 자 물 쇠 를 넣 지 않 고 충돌 이 없다 고 가정 하여 어떤 조작 을 완성 하 는 것 이다.충돌 이 실패 하면 성공 할 때 까지 다시 시도 하 는 것 이다.
잠 금 에 비해 volatile 변 수 는 더 가 벼 운 동기 화 체제 입 니 다.이 변 수 를 사용 할 때 문맥 전환 과 스 레 드 스케줄 링 등 이 발생 하지 않 지만 volatile 은 원자 문 제 를 해결 할 수 없 기 때문에 변수 가 이전 값 에 의존 할 때 volatile 변 수 를 사용 할 수 없습니다.따라서 동기 화 에 대해 서 는 결국 잠 금 장치 로 돌아 가 야 한다.
낙관적 자물쇠
낙관 자물쇠(Optimistic Locking)는 사실 일종 의 사상 이다.비관 적 인 자물쇠 에 비해 낙관적 인 자 물 쇠 는 데이터 가 일반적인 상황 에서 충돌 하지 않 는 다 고 가정 하기 때문에 데이터 가 업 데 이 트 를 제출 할 때 데이터 의 충돌 여 부 를 본 격 적 으로 검 측 하고 충돌 이 발견 되면 사용자 의 잘못된 정 보 를 되 돌려 사용자 가 어떻게 할 것 인 가 를 결정 하도록 한다.
위 에서 언급 한 낙관적 자물쇠 의 개념 에서 사실은 그의 구체 적 인 실현 세부 사항 을 논술 했다.주로 두 가지 절차 가 있다.충돌 검 측 과 데이터 업데이트 이다.그 실현 방식 은 비교적 전형 적 인 것 이 바로 Compare and Swap(CAS)이다.
CAS
CAS 는 낙관적 인 잠 금 기술 입 니 다.여러 스 레 드 가 CAS 를 사용 하여 같은 변 수 를 동시에 업데이트 하려 고 시도 할 때 그 중의 한 스 레 드 만 변수의 값 을 업데이트 할 수 있 고 다른 스 레 드 는 모두 실 패 했 습 니 다.실패 한 스 레 드 는 걸 리 지 않 고 이번 경쟁 에서 실 패 했 음 을 알 리 고 다시 시도 할 수 있 습 니 다.
CAS 작업 은 메모리 위치(V),예상 원 치(A),새 값(B)세 개 를 포함 합 니 다.메모리 위치의 값 이 원 하 는 값 과 일치 하면 프로세서 가 자동 으로 이 위치 값 을 새 값 으로 업데이트 합 니 다.그렇지 않 으 면 프로세서 가 아무런 조작 도 하지 않 습 니 다.어떤 경우 에 도 CAS 명령 전에 이 위치의 값 을 되 돌려 줍 니 다.(CAS 의 일부 특수 한 상황 에서 현재 값 을 추출 하지 않 고 CAS 의 성공 여부 만 되 돌려 줍 니 다.)CAS 는"위치 V 는 값 A 를 포함해 야 한다 고 생각한다.이 값 을 포함 하면 B 를 이 위치 에 놓 습 니 다."그렇지 않 으 면 이 위 치 를 바 꾸 지 말고 이 위치의 현재 값 만 알려 주면 됩 니 다."이 는 낙관 자물쇠 의 충돌 검사+데이터 업데이트 원리 와 같다.
여기 서 다시 한 번 강조 하 자 면,낙관 의 자 물 쇠 는 일종 의 사상 이다.CAS 는 이런 사상의 일종 의 실현 방식 이다.
CAS 에 대한 자바 지원
JDK 1.5 에 자바 util.concurrent(J.U.C)를 추가 하 는 것 은 CAS 위 에 세 워 진 것 이다.synchronized 라 는 차단 알고리즘 에 비해 CAS 는 비 차단 알고리즘 의 흔 한 구현 입 니 다.그래서 J.U.C 는 성능 이 크게 향상 되 었 다.
자바 util.concurrent 의 Atomic Integer 를 예 로 들 어 자 물 쇠 를 사용 하지 않 은 상태 에서 스 레 드 안전 을 어떻게 보장 하 는 지 살 펴 보 겠 습 니 다.getAndIncrement 방법 을 주로 이해 하 는데 이 방법의 작용 은++i 조작 에 해당 한다.
public class AtomicInteger extends Number implements java.io.Serializable {
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;
public AtomicInteger(int initialValue) {
value = initialValue;
}
public final int get() {
return value;
}
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
잠 금 이 없 는 메커니즘 에서 필드 value 가 필요 합 니 다.volatile 원 어 를 통 해 스 레 드 간 의 데 이 터 를 볼 수 있 도록 해 야 합 니 다.이렇게 해 야 변수의 값 을 가 져 올 때 직접 읽 을 수 있 습 니 다.그리고++i 가 어떻게 하 는 지 보 자.
getAndIncrement 는 메모리 에서 데 이 터 를 읽 을 때마다 이 데이터 와+1 후의 결 과 를 CAS 작업 을 하고 성공 하면 결 과 를 되 돌려 줍 니 다.그렇지 않 으 면 성공 할 때 까지 다시 시도 합 니 다.compare AndSet 은 JNI 를 이용 하여 CPU 명령 을 수행 합 니 다.
ABA 문제
CAS 는'ABA 문제'로 이 어 질 수 있다.
CAS 알고리즘 은 중요 한 전 제 를 실현 하려 면 메모리 의 특정한 시간의 데 이 터 를 꺼 내 고 다음 시간 에 비교 하고 교체 해 야 한다.그러면 이 시간 차 류 는 데이터 의 변 화 를 초래 할 수 있다.
예 를 들 어 하나의 스 레 드 one 은 메모리 위치 V 에서 A 를 꺼 냈 다.이때 다른 스 레 드 two 도 메모리 에서 A 를 꺼 냈 고 two 는 일부 조작 을 해서 B 가 되 었 다.그리고 two 는 V 위치의 데 이 터 를 A 로 만 들 었 다.이때 스 레 드 one 은 CAS 작업 을 했 는데 메모리 에 A 가 있 는 것 을 발견 했다.그 후에 one 작업 이 성공 했다.스 레 드 원 의 CAS 작업 이 성 공 했 음 에 도 불구 하고 이 과정 이 문제 가 없다 는 것 은 아니다.
일부 낙관 잠 금 의 실현 은 버 전 번호(version)를 통 해 ABA 문 제 를 해결 하 는 것 이다.낙관 잠 금 은 데이터 수정 작업 을 수행 할 때마다 버 전 번호 와 데이터 버 전 번호 가 일치 하면 수정 작업 을 수행 하고 버 전 번호 에 대해+1 작업 을 수행 할 수 있 으 며 그렇지 않 으 면 실 패 를 할 수 있다.매번 작 동 하 는 버 전 번호 가 그 만큼 늘 어 나 기 때문에 ABA 문제 가 발생 하지 않 고 버 전 번호 만 늘 어 나 고 줄 어 들 지 않 기 때문이다.
총결산
자바 의 스 레 드 안전 문 제 는 매우 중요 하 다.스 레 드 안전 을 확보 하려 면 잠 금 장치 가 필요 하 다.자물쇠 메커니즘 은 낙관적 자물쇠 와 비관 적 자 물 쇠 를 포함한다.비관 적 인 자 물 쇠 는 독점 자물쇠 로 자 물 쇠 를 막는다.낙관적 인 자 물 쇠 는 독점 자물쇠 가 아니 라 차단 자물쇠 가 아니다.낙관적 인 자물쇠 의 실현 방식 은 바로 CAS 인 데 이런 알고리즘 은 JDK 1.5 에 도 입 된 java.util.concurrent 에서 광범 위 하 게 응용 된다.그러나 주의해 야 할 것 은 이런 알고리즘 에 ABA 문제 가 존재 할 수 있다 는 점 이다.
CAS 와 대상 생 성
또 CAS 는 JVM 이 대상 을 만 드 는 과정 에서 도 하나의 애플 리 케 이 션 이 있다.대상 생 성 은 가상 컴퓨터 에서 매우 빈번 하 다.하나의 포인터 가 가리 키 는 위 치 를 수정 하 더 라 도 동시 다발 상황 에서 스 레 드 가 안전 하지 않 습 니 다.대상 A 에 게 메모리 공간 을 분배 하고 있 을 수 있 습 니 다.지침 이 아직 수정 되 지 않 았 고 대상 B 는 원래 의 지침 을 사용 하여 메모 리 를 분배 하 는 상황 입 니 다.이 문 제 를 해결 하 는 방안 은 두 가지 가 있 는데,그 중 하 나 는 CAS 에 실패 한 재 시도 방식 으로 업데이트 작업 의 원자 성 을 확보 하 는 것 이다.
레 퍼 런 스
비 차단 동기 화 알고리즘 과 CAS(Compare and Swap)잠 금 알고리즘 없 음:http://www.cnblogs.com/Mainz/p/3546347.html 질문http://www.cnblogs.com/549294286/p/3766717.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
《 나 는 병발 을 모른다 》 너 는 왜 아직도 라인 의 안전 을 모 르 니?1. 스 레 드 안전 이란 무엇 입 니까? 예: 다음 프로그램 은 라인 이 안전 합 니까? 2. 라인 안전 을 해결 하 는 일반적인 수단 자물쇠 (synchronized, volatile, Lock) 대기 열 (패키...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.