자바 인용 할당 은 원자 조작 입 니까?

11200 단어 자바
원본 링크:https://88250.b3log.org/java-atomic-conncurrent
간단 한 예 에서 병행 처리 할 때 무시 되 기 쉬 운 함정 을 끌 어 내 면접 문제 로 적합 할 것 이다.
어느 날, 4 년 넘 게 일 한 자바 프로그래머 K 군 이 이 직 했 는데 면접 에서 이런 문 제 를 만 났 는데...
public class P1 {
	private long b = 0;
	
	public void set1() {
		b = 0;
	}
	
	public void set2() {
		b = -1;
	}
	
	public void check() {
		System.out.println(b);
	
		if (0 != b && -1 != b) {
			System.err.println("Error");
		}
	 }
}


문제.
set 1 (), set 2 (), check () 을 호출 하면 오류 가 인쇄 됩 니까?
작은 K 의 추리
"set 1 (), set 2 () - > b 의 값 을 어떻게 호출 하 든 0 또는 - 1 - > check () 에서 의 판단 조건 (b 는 0 도 아니 고 - 1 도 아 닌) 은 영원히 성립 되 지 않 습 니 다 - > 인쇄 되 지 않 습 니 다 Error"
작은 K 는 구덩이 가 있다 고 생각 했다. 이 문 제 는 이렇게 간단 하지 않 을 것 이다. 다 중 스 레 드 환경 을 다시 생각해 보 자.
곰 곰 이 생각해 보 니 K 군 은 "다 중 스 레 드 환경 에서 도 Error 를 인쇄 하지 않 는 다. 이 문 제 는 간단 하 다. 추 리 를 살 펴 보 는 것 이다." 라 고 결론 을 내 렸 다. K 는 몰래 기뻐 했다.
이후 K 군 은 여러 스 레 드 와 JVM 에 대한 질문 을 받 았 다.
나중에... 나중에 없 었 어 요...
나중
나중에 도 있었어 요.집에 도착 하 자 달 갑 지 않 은 K 군 은 그 를 죽 이 는 면접 문 제 를 검증 했다.
public static void main(final String[] args) {
		final P1 v = new P1();
		//    1:   b = 0
		final Thread t1 = new Thread() {
			public void run() {
				while (true) {
					v.set1();
				}
			};
		};
		t1.start();
	
		//    2:   b = -1
		final Thread t2 = new Thread() {
			public void run() {
				while (true) {
					v.set2();
				}
			};
		};
		t2.start();
	
		//    3:   0 != b && -1 != b
		final Thread t3 = new Thread() {
			public void run() {
				while (true) {
					v.check();
				}
			};
		};
		t3.start();
	}

3 개의 스 레 드 를 사용 하여 각각 set 1 (), set 2 (), check () 을 반복 합 니 다.출력 결과 부분 은 다음 과 같 습 니 다.
....
0
0
1
1
1
Error
Error
-4294967296
0
0
4294967295
....

실행 환경: Java™ SE Runtime Environment (build 1.6.0_31-b05) Java HotSpot™ Client VM (build 20.6-b01, mixed mode, sharing), 32bit
"확실히 Error 를 인쇄 했 고 4294967295, - 42944967296 을 인쇄 했 습 니 다. 제 가 졸 라 보 겠 습 니 다. 다만 어떤 상황 입 니까?"
K 군 은 그 비밀 을 알 아 보기 로 하고 제목 을 재 검토 했다.전문 프로그래머 로 서 엄격 하고 수 차례 구 글 을 거 친 후에 그 는 문제점 을 발견 한 것 같다.
"이것 은 확실히 병발 문제 다!"
분석 하 다.
이 문 제 는 두 개의 함정 이 있 는데 각각 병행 집행 에 대한 이해 와 JVM 기초 (할당 작업) 에 대한 파악 을 고찰 했다.
함정 1: 동시 실행
동시 실행 은 여러 동작 이 함께 실행 되 고 CPU 가 서로 다른 컨 텍스트 (서로 다른 스 레 드 로 이해 할 수 있 음) 에서 보 내 온 명령 입 니 다.운영 체제 상층 부 는 병행 처리 처럼 보인다.
즉, 프로 그래 밍 언어 차원 에서 간단 한 조작 도 병행 문 제 를 고려 해 야 한 다 는 것 이다.
작은 K 는 먼저 check () 에 심 은 if 판단 과 설정 값 이 병발 하 는 것 이 므 로 0 을 보장 할 수 없습니다! =b. 이 판단 진 (이때 b 는 - 1) 후 마침 b 가 0 으로 할당 되 었 을 때 1 을 판단 합 니 다! =b。
그 밖 에 JVM, 운영 체제, CPU 차원 에서 명령 을 어떻게 최적화 하고 재배 치 하 든 결국은 단일 명령 을 하나씩 집행 하 는 것 이다. 유일한 차이 점 은 서로 다른 차원 에서 집행 에 제한 을 가 할 수 있다 는 것 이다.
예 를 들 어 원자 조작 에 가입 하면 CPU 가 명령 을 완전히 수행 할 수 있 도록 한다.
함정 2: JVM 할당 작업
일부 할당 작업 은 원자 적 인 것 이 아니다."나 니?"
자바 의 기본 유형 중 롱 과 더 블 은 64 비트 길이 입 니 다.32 비트 구조 CPU 의 산술 논리 장치 (ALU) 너 비 는 32 비트 이 며 32 비트 이상 의 동작 을 처리 할 때 두 번 처리 해 야 한다.
"그 렇 잖 아" 라 고 K 군 은 대학 에 헛 다 니 는 것 을 느 꼈 고 배 울 줄 모 르 고 TT~
제목 집행 인쇄 4294967295, - 42944967296 은 읽 을 때 높 은 32 자리 나 낮은 32 자리 가 다른 쓰기 에 덮 여 있 기 때문이다 (이 두 숫자의 바 이 너 리 를 보면 알 수 있다).
자바 는 이미 바 텀 디 테 일 을 봉인 하 는 좋 은 언어 이지 만 이러한 함정 에 주의해 야 합 니 다. 병렬 처리 패키지 자바 util. concurrent. atomic 에 일련의 잠 금 없 는 원자 조작 유형 을 포함 할 수 있 습 니 다.
volatile 키 워드 를 사용 하여 스 레 드 간 변수의 가시 성 을 확보 할 수 있 습 니 다.
사실 이 문 제 는 병발 문 제 를 해결 하기 만 하면 모든 실행 단원 (set 1 (), set 2 (), check () 에서 값 을 부여 하고 비교 하 는 정확성 을 보장 한다.동기 화 방법 을 직렬 화 된 업무 로 볼 수 있 고 각 작업 은 서로 영향 을 주지 않 습 니 다.
나중
K 군 면접 은 끊 었 지만 그 는 심복 했다.
그 동안 의 문서 열람 과 실험 을 통 해 K 군의 다음 면접 은 비슷 한 문제 에 의 해 순식간에 죽 지 는 않 을 것 입 니 다.
"이 간단 한 면접 문제 의 기준 에 따 르 면, 이전에 쓴 프로그램 은 그야말로 전체 bugs 입 니 다! 나무 도 있 고 나무 도 있 습 니 다!!!!"
소 년 아, 계속 충전 해라!
안팎 을 겸 수 하 는 것 이 야 말로 좋 은 프로그래머 다.
64 비트 os 에서 측정 한 결과 건물 주의 프로그램 은 ERROR 를 인쇄 하지 않 을 것 이다. 나 는 다음 과 같은 원인 이 라 고 추측 했다. 1) long 은 64 비트 의 문제 이다.32 비트 os 에 서 는 고 32 비트 와 저 32 비트 의 문 제 를 쓰 고 64 비트 기계 에 서 는 문제 가 없 는 것 같 습 니 다. 2) if 의 두 가지 판단 문제.스 레 드 는 자신의 스 택 과 레지스터 가 있 기 때문에 스 레 드 3 은 if 에서 b 를 읽 은 후에 두 번 째 로 자신의 레지스터 에서 'private long b = 0;' 을 읽 은 것 같 습 니 다. 'private volatile long b = 0;' 으로 바 꾼 후에 ERROR 를 인쇄 할 수 있 습 니 다. 원 리 는 volatile 이 스 레 드 에 매번 메모리 에서 b 를 읽 으 라 고 요구 하 는 것 입 니 다. 여러분 이 믿 지 않 으 면 시험 해 보 세 요. 실험 은 진 리 를 검증 하 는 유일한 표준 입 니 다.

좋은 웹페이지 즐겨찾기