자바 대기 각성 메커니즘 원리 및 사용
이것 은 심혈 을 기울 인 구덩이 메 우기 노트 입 니 다.자바 를 독학 한 몇 년 동안 새로운 기술 을 계속 배 웠 습 니 다.걸 어 오 면서 자신 이 구 덩이 를 많이 밟 았 다 는 것 을 알 게 되 었 고 채 워 진 구 덩이 는 손 에 꼽 을 수 있 습 니 다.갑자기 가끔 은 정말 몇 년 의 업무 경험 이 문제 가 아니 라 10 년 동안 일 해도 열심히 공부 하지 않 은 것 이 10 년 의 큰 구덩이 에 불과 하 다 는 것 을 알 게 되 었 다.
다 중 스 레 드 를 처음 접 했 을 때 이 물건 을 기다 리 거나 깨 울 줄 알 았 습 니 다.demo 라 고 쓰 면 다 시 는 보지 못 했 습 니 다.그것 이 도대체 무엇 인지,아니면 어떤 문 제 를 해결 할 수 있 는 지 에 대해 서 는 대부분의 사람들 이 저 와 마찬가지 로 애매모호 할 것 입 니 다.이번에 필 자 는 당신 을 데 리 고 기다 림/깨 우기 체 제 를 이해 하려 고 합 니 다.본 고 를 읽 으 면 다음 과 같은 몇 가 지 를 얻 을 것 입 니 다.
만약 에 오늘 월급 을 주 려 고 한다 면 강 사장 은 좋 은 음식 을 먹 으 러 가 야 한다.전체 식사 절 차 는 다음 과 같은 몇 가지 절차 로 나 눌 수 있다.
public static void main(String[] args) {
//
AtomicBoolean hasBun = new AtomicBoolean();
//
new Thread(() -> {
try {
//
while (true) {
if (hasBun.get()) {
System.out.println(" : ...");
Thread.sleep(3000);
} else {
System.out.println(" : , ...");
Thread.sleep(1000);
System.out.println(" : ....");
hasBun.set(true);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
System.out.println(" : ...");
try {
//
while (!hasBun.get()) {
System.out.println(" : ~");
Thread.sleep(3000);
}
System.out.println(" : ....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
위의 코드 에 큰 문제 가 존재 한다.바로 사장 이 만두 가 있 는 지 계속 검사 해 야 하고 고객 은 일정 시간 간격 으로 사장 을 보 러 가 야 한다.이것 은 분명 합 리 적 이지 않다.이것 이 바로 전형 적 인 순환 대기 문제 이다.
이런 문제 의 코드 에는 보통 다음 과 같은 모델 이 있다.
while ( ) {
Thread.sleep(3000);
}
doSomething();
컴퓨터 에 대응 하면 하나의 문제 가 드 러 났 다.폴 링 체 제 를 통 해 조건 이 성립 되 는 지 계속 검 측 하고 폴 링 시간 이 너무 적 으 면 CPU 자원 을 낭비 할 수 있 으 며 간격 이 너무 크 면 원 하 는 자원 을 신속하게 얻 지 못 할 수도 있다.둘째,대기/깨 우기 메커니즘
순환 대기 CPU 소모 및 정보 신속 성 문 제 를 해결 하기 위해 자바 에 서 는 대기 각성 체 제 를 제공 합 니 다.쉽게 말 하면 주동 에서 수 동적 으로 바 뀌 고 조건 이 성립 될 때 해당 하 는 스 레 드 를 주동 적 으로 통지 하 는 것 이지 스 레 드 자체 에 문의 하 게 하 는 것 이 아니다.
2.1 기본 개념
대기/깨 우기 메커니즘 은 대기 알림(필 자 는 알림 이 아 닌 깨 우기)이 라 고도 부른다.스 레 드 A 가 대상 O 의 wait()방법 을 호출 하여 대기 상태 에 들 어 갔 고 다른 스 레 드 는 O 의 notify()또는 notify All()방법 을 호출 했다.스 레 드 A 가 통 지 를 받 은 후에 대상 O 의 wait()방법 으로 돌아 와 후속 작업 을 수행 했다.
항소 과정 은 대상 O 를 통 해 스 레 드 A 와 스 레 드 B 간 에 통신 을 하고 스 레 드 에서 대상 O 의 wait()방법 을 호출 한 후 스 레 드 가 오랫동안 차단 상태 에 들 어 갔 으 며 다른 스 레 드 에서 대상 O 가 notify()또는 notify All 방법 을 호출 할 때 해당 하 는 차단 스 레 드 를 깨 웁 니 다.
2.2 기본 API
시스템 에 대한 방법 을 기다 리 거나 깨 울 때 임의의 자바 대상 이 갖 추고 있 습 니 다.이 방법 들 은 모든 자바 대상 의 초 클래스 Object 에 정의 되 어 있 기 때 문 입 니 다.
notify:대상 에서 기다 리 는 스 레 드 를 wait()방법 으로 되 돌려 주 고 되 돌아 오 는 전제 에서 대상 의 자 물 쇠 를 가 져 옵 니 다.
notify All:이 대상 을 기다 리 는 모든 스 레 드 를 알려 줍 니 다.
wait:이 방법 을 사용 하 는 스 레 드 는 차단 대기 상태 에 들 어 갑 니 다.다른 스 레 드 의 알림 을 기다 리 거나 중단 되 어야 돌아 갑 니 다.wait 방법 을 사용 하면 대상 의 자 물 쇠 를 풀 수 있 습 니 다.
wait(long):한 동안 깨 어 나 지 않 으 면 시간 을 초과 하여 자동 으로 돌아 갑 니 다.단 위 는 밀리초 입 니 다.
2.3 대기 각성 메커니즘 으로 순환 대기 최적화
public static void main(String[] args) {
//
AtomicBoolean hasBun = new AtomicBoolean();
//
Object lockObject = new Object();
//
new Thread(() -> {
try {
while (true) {
synchronized (lockObject) {
if (hasBun.get()) {
System.out.println(" : , ");
lockObject.wait();
} else {
System.out.println(" : , ...");
Thread.sleep(3000);
System.out.println(" : ....");
hasBun.set(true);
//
lockObject.notifyAll();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
System.out.println(" : ...");
try {
synchronized (lockObject) {
if (!hasBun.get()) {
System.out.println(" : , cruder ");
lockObject.wait();
} else {
System.out.println(" : , ....");
hasBun.set(false);
lockObject.notifyAll();
System.out.println(" : , ~~");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
상기 절 차 는 폴 링 검사 의 조작 을 줄 이 고 스 레 드 가 wait()방법 을 호출 한 후에 자 물 쇠 를 방출 하여 CPU 자원 을 소모 하지 않 고 프로그램의 성능 을 향상 시 켰 다.
3.깨 우기 메커니즘 의 기본 패 러 다 임 을 기다린다.
대기,깨 우 는 것 은 스 레 드 간 통신 의 수단 중 하나 로 여러 스 레 드 가 같은 데이터 소스 를 조작 하 는 것 을 조율 하 는 데 사용 된다.실제 응용 에서 순환 대기 문 제 를 최적화 시 키 고 대기 자 와 통지 자 를 대상 으로 다음 과 같은 전형 적 인 범례 를 추출 할 수 있다.
주의해 야 할 것 은 대기 자가 실행 하 는 논리 에서 while 순환 으로 대기 조건 을 판단 해 야 한 다 는 것 입 니 다.notify/notify All 방법 을 실행 할 때 대기 스 레 드 를 wait 방법 에서 되 돌려 주 는 것 이지 임계 구역 에 다시 들 어 가 는 것 이 아 닙 니 다.
/**
*
* 1.
* 2. , , wait ,
* 3.
*/
synchronized( ){
while( ){
.wait()
}
doSomething();
}
/**
* !!
* 1.
* 2.
* 3. ( )
*/
synchronized( ){
.notify();
}
이 프로 그래 밍 패 러 다 임 은 전형 적 인 통지 자 와 대기 자 를 대상 으로 하 는 것 이 고 가끔 은 쌍방 이 이중 신분 을 가 질 수 있 으 며 대기 자 는 통지 자 이 더 라 도 우리 가 상기 한 사례 와 같다.4.notify/notifyAll 잠 금 해제 하지 않 음
이 문 제 는 엔지니어 의 절반 이 모 르 고 wait()방법 을 실행 하면 자물쇠 가 자동 으로 풀 려 날 것 이 라 고 믿 습 니 다.그러나 notify()방법 을 실행 한 후 자 물 쇠 는 풀 리 지 않 고 notify()방법 이 있 는 synchronized 코드 블록 을 실행 해 야 풀 립 니 다.이 점 은 매우 중요 하고 많은 엔지니어 들 이 소홀히 하기 쉬 운 부분 이다.
lockObject.notifyAll();
System.out.println(" : , ~~");
사례 코드 에서 일부러 notify All 로 설정 한 다음 에 인쇄 합 니 다.위의 그림 에서 의 결과 도 우리 의 묘 사 를 입증 했다.관심 이 있 는 파트너 는 사례 코드 를 실행 할 수 있다.5.대기,각성 은 먼저 자 물 쇠 를 가 져 와 야 합 니 다.
대기,깨 우기 프로 그래 밍 모드 에서 wait,notify,notify All 방법 은 직접 호출 되 지 않 습 니 다.잠 금 을 가 져 온 임계 구역 에서 실행 해 야 합 니 다.
그리고 같은 자물쇠 에 기다 리 는 스 레 드 만 깨 울 수 있 습 니 다.
스 레 드 가 wait 방법 을 호출 할 때 대기 열 에 가입 합 니 다.notify 를 실행 할 때 대기 열 에 있 는 첫 번 째 대기 스 레 드(대기 시간 이 가장 긴 스 레 드)를 깨 우 고 notify All 을 호출 할 때 대기 스 레 드 에 있 는 모든 대기 스 레 드 를 깨 웁 니 다.
6,sleep 자 물 쇠 를 풀 지 않 고 wait 방출\#
대기 깨 우기 메커니즘 으로 순환 기다 림 을 최적화 하 는 과정 에서 중요 한 특징 은 원래 의 sleep()방법 을 wait()방법 으로 대체 하 는 것 이다.그들의 가장 큰 차이 점 은 wait 방법 은 자 물 쇠 를 방출 하 는 것 이 고 sleep 는 그렇지 않다 는 것 이다.그 밖 에 중요 한 차이 점 이 있다.sleep 는 Thread 의 방법 으로 임 의적 으로 실행 할 수 있다.wait 는 Object 대상 의 방법 으로 synchronized 코드 블록 에서 실행 해 야 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.