자바 volatile 키워드 역할 및 사용 장면 상세 설명
public class VolatileTest3 {
static class Work {
boolean isShutDown = false;
void shutdown() {
isShutDown = true;
System.out.println("shutdown!");
}
void doWork() {
while (!isShutDown) {
System.out.println("doWork");
}
}
}
public static void main(String[] args) {
Work work = new Work();
new Thread(work::doWork).start();
new Thread(work::doWork).start();
new Thread(work::doWork).start();
new Thread(work::shutdown).start();
new Thread(work::doWork).start();
new Thread(work::doWork).start();
new Thread(work::doWork).start();
}
}
더러 운 읽 기 가 발생 했 을 때 실행 결 과 는 다음 과 같 습 니 다.2.왜 더러 운 독 서 를 하 는가?
자바 메모리 모델 은 모든 변 수 를 메 인 메모리 에 존재 하도록 규정 하고 모든 스 레 드 는 자신의 작업 메모리 가 있 습 니 다.스 레 드 는 변수의 모든 작업 을 작업 메모리 에서 해 야 하 며,메 인 저장 소 를 직접 조작 할 수 없습니다.또한 모든 스 레 드 는 다른 스 레 드 의 작업 메모리 에 접근 할 수 없습니다.변수의 값 이 스 레 드 의 작업 메모리 에서 메 인 메모리 로 언제 돌아 올 지 확인 할 수 없습니다.
3.happens-before 규칙 의 이해 와 교정
인터넷 에서 volatile 키워드 와 관련 된 정 보 를 찾 을 때 여러 블 로 그 는 happens-before 원칙 을 언급 했다.개인 은 이 원칙 에 대한 이 해 는 이 volatile 변 수 를 조작 할 때 모든 순서 가 이 변수 에 대한 작업 이 완료 되 었 다(변 경 된 것 이 없 지만 메 인 저장 소 에 쓰 이지 않 은 경우)는 것 이다.모든 후속 적 인 이 변수 에 대한 작업 은 시작 되 지 않 았 다.그 뿐 입 니 다.
여기 서 나 는 인터넷 에서 흔히 볼 수 있 는 이론 이 이에 대한 이해 가 잘못 되 었 다 고 생각한다.다음 과 같다.이 관점 에 따 르 면 volatile 변수 flag 의 happens-before 원칙 으로 인해 A 스 레 드 2 곳 의 쓰기 동작 은 반드시 B 스 레 드 3 곳 의 읽 기 동작 보다 앞 선다.사실 이러한 관점 은 논리 적 결함 이 있 습 니 다.만약 에 C 스 레 드 가 존재 한다 면 먼저 flag 의 값 을 읽 은 다음 에 flag 의 값 을 기록 합 니 다.그러면 C 스 레 드 의 실행 시 기 는 무엇 입 니까?다른 D,E 라인 이 있다 면...이 코드 에 대한 정확 한 이 해 는 3 곳 에서 받 은 flag 가 true 라면 a 의 값 은 0 이 아니 라 1 이 어야 한 다 는 것 입 니 다.volition 수식 변수 때문에 프로세서 가 정렬 을 다시 하지 않 기 때문에 1 곳 에서 a 에 대한 할당 은 반드시 2 곳 에서 flag 에 대한 할당 전에 발생 합 니 다.flag 가 volatile 변수 가 아니라면 1 곳 과 2 곳 코드 의 실행 순 서 는 보장 되 지 않 습 니 다(프로세서 의 명령 재 정렬).대부분의 경우 1 이 2 보다 먼저 실행 되 지만.happens-before 원칙 은 다 중 스 레 드 가 같은 변수 에 대한 읽 기와 쓰기 작업 간 의 순서 가 아니 라 읽 기 작업 을 보장 할 때 이 변수 에 대한 모든 쓰기 작업 이 유효 합 니 다(메 인 저장 소 에 쓰기).
인증 은 다음 과 같 습 니 다:
public class VolatileTest {
static class A {
int a = 0;
volatile boolean flag = false;
void writer() {
a = 1; //1
flag = true; //2
System.out.println("write");
}
void reader() {
if (flag) { //3
int i = a; //4
System.out.println("read true");
System.out.println("i is :" + i);
} else {
int i = a;
System.out.println("read false");
System.out.println("i is :" + i);
}
}
}
public static void main(String[] args) {
A aaa = new A();
new Thread(() -> aaa.reader()).start();
new Thread(() -> aaa.writer()).start();
}
}
실행 결 과 는 다음 과 같 습 니 다.쓰기 작업 이 실행 되 기 전에 읽 기 작업 이 완료 되 었 습 니 다.4.volatile 키워드 사용 필드
주의:volatile 은 변수의 가시 성 만 확보 할 수 있 고 volatile 변수 에 대한 원자 성 은 보장 할 수 없습니다.다음 코드 를 보십시오.
public class VolatileTest2 {
static class A {
volatile int a = 0;
void increase() {
a++;
}
int getA(){
return a;
}
}
public static void main(String[] args) {
A a = new A();
new Thread(() -> {
for (int i = 0;i < 1000;i++) {
a.increase();
}
System.out.println(a.getA());
}).start();
new Thread(() -> {
for (int i = 0;i < 2000;i++) {
a.increase();
}
System.out.println(a.getA());
}).start();
new Thread(() -> {
for (int i = 0;i < 3000;i++) {
a.increase();
}
System.out.println(a.getA());
}).start();
new Thread(() -> {
for (int i = 0;i < 4000;i++) {
a.increase();
}
System.out.println(a.getA());
}).start();
new Thread(() -> {
for (int i = 0;i < 5000;i++) {
a.increase();
}
System.out.println(a.getA());
}).start();
}
}
실행 결 과 는 다음 과 같 습 니 다.volatile 은 a+작업 의 원자 성 을 보장 할 수 없습니다.volatile 의 정확 한 사용 방법 은 참고 할 수 있 습 니 다https://www.jb51.net/article/166888.htm
이상 이 바로 이번 지식 점 을 소개 하 는 모든 내용 입 니 다.여러분 의 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.