자바 다 중 스 레 드 CAS 조작 원리 코드 인 스 턴 스 분석
1.다음은 AtomicInteger 의 사용:
package com.designmodal.design.juc01;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author D-L
* @Classname T03_AtomicInteger
* @Version 1.0
* @Description AtomicInteger count++
* CAS
* @Date 2020/7/21 0:35
*/
public class T03_AtomicInteger {
// AtomicInteger
AtomicInteger count = new AtomicInteger(0);
public void m(){
for (int i = 0; i < 10000; i++) {
// count++
count.incrementAndGet();
}
}
public static void main(String[] args) {
T03_AtomicInteger t = new T03_AtomicInteger();
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m , "Thread" + i));
}
threads.forEach((o) -> o.start());
threads.forEach(o ->{
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
2.물론 사용 하 는 단계 에 이 르 면 간단 합 니 다.API 를 보시 면 됩 니 다.위의 작은 프로그램 을 통 해 다음 과 같은 원 리 를 말씀 드 리 겠 습 니 다.1.소스 코드 분석 을 통 해 AtomicInteger
우선 애플 릿 에서 AtomicInteger 형식의 변수 count 를 정의 합 니 다.
AtomicInteger count = new AtomicInteger(0);
public void add(){
count.incrementAndGet();
}
AtomicInteger 클래스 에서 increment AndGet()을 호출 했 습 니 다.
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
unsafe 클래스 의 getAndAddInt(Object var 1,long var 2,int var 4)방법 을 호출 합 니 다.
public native int getIntVolatile(Object var1, long var2);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
여기 서 상기 세 단계 의 조작 을 통 해 최종 적 으로 Unsafe 류 에 들 어 갈 것 입 니 다.여기 서 호출 된 compare AndSwapInt 는 비교 한 다음 에 교환 하 는 것 입 니 다.while 순환 을 통 해 수정 이 성공 할 때 까지 여기 서 돌 고 돌 립 니 다.CAS(compare AndSwap)(비교 및 교환):원래 바 꾸 려 고 했 던 값 이 0 이 었 는데 지금 은 1 로 바 꾸 려 면 스 레 드 안전 을 하려 면 synchronized 를 추가 해 야 합 니 다.지금 은 다른 방식 으로 잠 금 을 추가 하 는 방법 을 바 꾸 려 고 합 니 다.바로 CAS 작업 입 니 다.세 개의 인 자 를 가 진 방법 카 스(V,Expected,NewValue)라 고 상상 할 수 있 습 니 다.첫 번 째 매개 변수 V 는 당신 이 고 치 려 는 값 입 니 다.expected 두 번 째 매개 변 수 는 현재 값 이 얼마 인지(즉,스 레 드 가 수정 되 지 않 았 을 때 이 값 이 얼마 인지,기대치 가 아니라면 다른 스 레 드 가 수정 되 었 음 을 증명 합 니 다)입 니 다.NewValue 는 설정 할 새 값 입 니 다.
위의 그림 은 CAS 작업 과정 을 간단하게 모 의 했 습 니 다.스 레 드 1 과 스 레 드 2 가 공유 변수 count=0 을 동시에 읽 었 을 때;스 레 드 1 을 수정 하 는 과정 에서 스 레 드 2 는 count 값 을 1 로 바 꾸 었 습 니 다.그러면 스 레 드 1 을 수정 할 때 expected 값 이 V 와 일치 하지 않 는 것 을 발 견 했 습 니 다.스 레 드 가 있 음 을 증명 합 니 다.저 는 한 걸음 에 count 값 을 바 꾸 었 습 니 다.(여기 서 병발 량 이 많 을 때 n 여 개의 스 레 드 가 수정 되 었 을 수도 있 습 니 다)어떻게 해 야 합 니까?그러면 저 는 제 기대 치 를 V 의 값 으로 수정 할 수 밖 에 없습니다.new Value 는 이 를 바탕 으로 1 을 더 한 다음 에 이 자전 작업 을 계속 할 수 있 습 니 다.수정 이 성공 할 때 까지 이것 이 바로 자전 작업 입 니 다.
2.Unsafe 류(자바 및 하 도 급 베이스 실현 의 핵심)
CAS 작업 에 자 물 쇠 를 넣 지 않 아 도 되 는데 어떻게 하 는 거 죠?원인 은 바로 Unsafe 와 같은 종류 입 니 다.이 종 류 는 반 사 를 사용 하 는 것 을 제외 하고 직접 사용 할 수 없습니다.여기 서 사용 할 수 없 는 원인 은 ClassLoader 와 관계 가 있 습 니 다.모든 AtomicXXX 류 내 부 는 CompareAndSwap/CompareAndSet(새 jdk)입 니 다.이 종 류 는 native 방법 이 많이 존재 합 니 다.
Unsafe 클래스 는 자바 로 하여 금 C 언어의 포인터 처럼 메모리 공간 을 조작 하 는 능력 을 가지 게 한다.메모 리 를 직접 조작 할 수 있다 면 이것 은(1)JVM 관 리 를 받 지 않 는 다 는 것 을 의미 하고 GC 에 의 해 수 동 GC 가 필요 하 다 는 것 을 의미 하 며 자칫 메모리 누 출 이 발생 할 수 있다.(2)Unsafe 의 많은 방법 중 원본 주소(메모리 주소)와 교 체 된 대상 의 주 소 를 제공 해 야 합 니 다.오프셋 은 스스로 계산 해 야 합 니 다.문제 가 발생 하면 JVM 붕괴 단계 의 이상 으로 인해 전체 JVM 인 스 턴 스 가 무 너 지고 응용 프로그램 이 직접 crash 로 표 시 됩 니 다.(3)메모 리 를 직접 조작 하 는 것 은 속도 가 빠 르 고 동시 다발 적 인 조건 에서 효율 을 잘 높 일 수 있다 는 것 을 의미한다.
CAS:CompareAndSwap,메모리 오프셋 주소(var 2),예상 값(var 4),새 값(var 5).변수 가 현재 시각 에 예상 치 expected 와 같 으 면 변수의 값 을 새 값(var 5)으로 업데이트 하려 고 합 니 다.업데이트 에 성공 하면 true 로 돌아 갑 니 다.그렇지 않 으 면 false 로 돌아 갑 니 다.
/**
* CAS :Unsafe Java ( : ),
* C C++
* @param var1
* @param var2
* @param var4
* @param var5
* @return true false
*/
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
3.CAS 조작 에 따 른 ABA 문제ABA 문 제 는 스 레 드 에서 CAS 작업 을 하 는 과정 에서 여러 개의 스 레 드 가 이 공유 변 수 를 수정 하고 감소 하 며 포켓 회전 이 다시 시작 값 으로 돌아 가 는 것 이다.이때 이 스 레 드 는 전혀 모른다.부적 절 한 비유:이 과정 은 마치 당신 의 전 여자친 구가 당신 과 헤 어 진 후 1 년 만 에 다시 당신 을 찾 아 온 것 같 습 니 다.돌아 다 니 는 것 이 좋 겠 다 고 말 했 습 니 다.그 동안 당신 의 전 여자친 구가 남자친구 몇 명 을 바 꿨 는데 당신 은 전혀 몰 랐 습 니 다.그 예 쁜 그녀 는 당신 이 좋아 하 는 짧 은 치 마 를 입고 청순 한 포 니 테 일 을 하고 다시 돌 아 왔 습 니 다.본론 으로 돌아 갑 니 다.결 과 는 당신 이 원 하 는 것 이지 만 이 값 은 많은 버 전 을 거 친 것 이다.
다음은 간단하게 ABA 조작 도 를 모 의 합 니 다.
어떻게 ABA 문 제 를 해결 합 니까?
int 유형 이 라면 최종 값 도 당신 이 원 하 는 것 입 니 다.정말 괜 찮 습 니 다.당신 도 이 문 제 를 고민 할 필요 가 없습니다.만약 당신 이 확실히 관리 하고 싶다 면 버 전 번 호 를 추가 하고 수정 작업 에 하 나 를 추가 하 며 비교 검 사 를 할 때 버 전 번 호 를 함께 검사 하 세 요.
기본 유형:상관 할 필요 없어.너 한 테 는 정말 상관 없어.
인용 유형:마치 당신 의 여자 친구 가 당신 과 헤 어 진 후에 다시 재결합 하 는 것 과 같 습 니 다.중간 에 몇 명의 남자 친 구 를 겪 었 는 지 는 상관 이 있 습 니 다.이 때 는 버 전 번 호 를 추가 해서 해결 할 수 있 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.