자바 의 다 중 스 레 드 와 병발volatile 키워드 의 깊 은 이해
volatile 은 JVM 이 제공 하 는 경량급 동기 화 메커니즘 으로 특성:
1.메모리 의 가시 성 확보
2.원자 성 을 보장 하지 않 는 다
3.명령 어 정렬 방지
2.JMM(Java Memory Model)
자바 메모리 모델 은 모든 변 수 를 주 메모리 에 저장 하도록 규정 하고 있 습 니 다(예 를 들 어 가상 컴퓨터 물리 메모리 의 일부분).모든 스 레 드 는 자신의 작업 메모리(예 를 들 어 CPU 의 고속 캐 시)가 있 습 니 다.스 레 드 의 작업 메모리 에는 이 스 레 드 가 사용 하 는 변 수 를 주 메모리 의 복사 본 에 저장 하고 스 레 드 는 변 수 를 모든 작업(읽 기,읽 기,할당)주 메모리 의 변 수 를 직접 읽 지 않 고 작업 메모리 에서 진행 해 야 합 니 다.서로 다른 스 레 드 간 에 상대방 의 작업 메모리 에 있 는 변 수 를 직접 방문 할 수 없습니다.스 레 드 간 변수 값 의 전달 은 모두 메 인 메모리 로 이 루어 져 야 합 니 다.스 레 드,메 인 메모리 와 작업 메모리 의 상호작용 관 계 는 다음 그림 과 같 습 니 다.
검증
1.volatile 의 가시 성 검증
1.1 만약 int num=0;num 변 수 는 이전에 volatile 키워드 수식 을 추가 하지 않 았 고 보이 지 않 았 습 니 다.
1.2 volatile 을 추가 하여 가시 적 인 문 제 를 해결 할 수 있 습 니 다.
MyData 클래스
class MyData {
volatile int num = 0;
public void addT060() {
this.num = 60;
}
}
메모리 가시 성 검증,그 중 두 스 레 드 는 각각 AAA 스 레 드 와 main 스 레 드 입 니 다.
//volatile , ,
@Test
public void seeOkByVolatile() {
MyData myData = new MyData();//
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t come in");
//
try{
TimeUnit.SECONDS.sleep(3);
}catch (InterruptedException e) {
e.printStackTrace();
}
myData.addT060();
System.out.println(Thread.currentThread().getName() + "\t update num value: " + myData.num);
},"AAA").start();
// 2 main
while (myData.num == 0) {
//main , num 0.
}
System.out.println(Thread.currentThread().getName() + "\t mission is over,main get num value: " + myData.num );
}
num 변수 에 volatile 수식 후 결과AAA come in
AAA update num value: 60
main AAA 스 레 드 가 num 에 대한 수정 결 과 를 볼 수 있 습 니 다.main get num value:60
Process finished with exit code 0
2.volatile 이 원자 성 을 보장 하지 않 는 지 검증
2.1 원자 성 이란 무슨 뜻 입 니까?
분할 할 수 없 는 완전 성,즉 특정한 스 레 드 가 특정한 임 무 를 하고 있 을 때 중간 에 끼어 들 거나 분할 되 어 서 는 안 된다.전체 가 온전 해 야 한다.동시에 성공 하거나 동시에 실패 하 다.
2.2 volatile 원자 성 을 보장 하지 않 는 사례 시연
2.3 왜 원자 성 을 보장 하지 않 습 니까?
2.4 원자 성 을 어떻게 보장 합 니까
동기 화 추가
저희 jc 하의 AtomicInteger 를 사용 하 세 요.
MyData 클래스 에 addPlus()방법 추가
class MyData {//MyData.java ===> MyData.class ===> JVM
int num = 0;
public void addT060() {
this.num = 60;
}
// , num ,volatile
public void addPlusPlus() {
num++;
}
}
2.2 volatile 원자 성 을 보장 하지 않 는 사례 시연num+다 중 스 레 드 작업 의 경우 원자 성 을 보장 하지 않 습 니 다.
20 개의 스 레 드 를 만 들 고 num+작업 2000 회 를 병행 합 니 다.여러 번 테스트 한 결과 40000 이 아 닙 니 다.
public static void main(String[] args) {
MyData myData = new MyData();
for (int i = 1; i <= 20; i++ ) {
new Thread(() -> {
for (int j = 1; j <= 2000; j++) {
myData.addPlusPlus();
}
},String.valueOf(i)).start();
}
// 20 , main ?
while(Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "\t finally num value:" + myData.num);
}
결과:수치 가 40000 보다 적 으 면 쓰기 값 을 잃 어 버 리 는 경우 가 발생 합 니 다.main finally num value:38480
Process finished with exit code 0
2.3 왜 원자 성 을 보장 하지 않 습 니까?
스 레 드 A 가 num+작업 을 자신의 작업 메모리 에서 메 인 메모리 로 갱신 할 때 다른 스 레 드 메 인 메모리 변수 가 업데이트 되 는 순간 까지 알 리 지 않 았 기 때문에 다른 스 레 드 가 num 변 수 를 조작 한 결과 도 메 인 메모리 에 새로 고침 을 하여 쓰기 값 이 손실 되 었 습 니 다.
num+어 셈 블 리 명령 분석 을 통 해 자바 p 역 컴 파일 을 통 해 다음 과 같은 어 셈 블 리 명령 을 얻 을 수 있 습 니 다.
class com.slx.juc.MyData {
volatile int num;
com.slx.juc.MyData();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #2 // Field num:I
9: return
public void addT060();
Code:
0: aload_0
1: bipush 60
3: putfield #2 // Field num:I
6: return
public void addPlusPlus();
Code:
0: aload_0
1: dup
2: getfield #2 // Field num:I
5: iconst_1
6: iadd
7: putfield #2 // Field num:I
10: return
}
이 를 통 해 알 수 있 듯 이 num++는 3 단계 로 나 뉘 어 져 있 으 며,약칭:읽 기-고치 기-쓰기2.4 원자 성 을 어떻게 보장 합 니까
동기 화 추가
저희 jc 하의 AtomicInteger 를 사용 하 세 요.
MyData 클래스 에 원자 류 조작 방법 추가
AtomicInteger atomicInteger = new AtomicInteger();
public void addMyAtomic() {
atomicInteger.getAndIncrement();
}
이 방법 으로 결 과 를 인쇄 합 니 다.
public static void main(String[] args) {
MyData myData = new MyData();
for (int i = 1; i <= 20; i++ ) {
new Thread(() -> {
for (int j = 1; j <= 2000; j++) {
myData.addMyAtomic();
}
},String.valueOf(i)).start();
}
// 20 , main ?
while(Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type ,finally num value:" + myData.atomicInteger);
}
테스트 결 과 는 40000 이 며,이전 int 형식의 손실 값 은 나타 나 지 않 습 니 다.main AtomicInteger type ,finally num value:40000
Process finished with exit code 0
총결산
자바 의 다 중 스 레 드 와 병발 에 관 한 이 편volatile 키워드 의 글 은 여기까지 입 니 다.자바 다 중 스 레 드 와 병발volatile 키워드 내용 은 저희 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JAVA 다 중 스 레 드 메커니즘 의 스 레 드 생 성target 을 실행 대상 으로 지정 한 name 을 이름 으로 하고 group 에서 참조 하 는 스 레 드 그룹의 일원 으로 새 Thread 대상 을 할당 합 니 다. 이 스 레 드 가 독립 된 Runnable 실...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.