wait()
동기화 된 블록 외부 에서 호출 하여 의미를 유지하면서 호출자 스레드를 일시 중단 할 수있는 경우 잠재적 손상은 무엇입니까 ?
구체적인 예제wait()
를 통해 동기화 된 블록 외부에서 호출 할 수있는 경우 어떤 문제가 발생하는지 설명해 보겠습니다 .
차단 대기열을 구현한다고 가정합니다 (API에 이미 대기열이 있음을 알고 있습니다 :)
첫 번째 시도 (동기화 없음)는 아래 줄을 따라 표시 될 수 있습니다.
class BlockingQueue {
Queue<String> buffer = new LinkedList<String>();
public void give(String data) {
buffer.add(data);
notify(); // Since someone may be waiting in take!
}
public String take() throws InterruptedException {
while (buffer.isEmpty()) // don't use "if" due to spurious wakeups.
wait();
return buffer.remove();
}
}
이것은 잠재적으로 일어날 수있는 일입니다.
소비자 스레드가 호출 take()
하고 buffer.isEmpty()
.
소비자 스레드가 계속 호출하기 전에 wait()
생산자 스레드가 와서 전체를 호출합니다 give()
.buffer.add(data); notify();
컨슈머 스레드는 이제 호출합니다 wait()
( 방금 호출 한 것을 놓치게됩니다notify()
).
운이 좋지 않으면 give()
소비자 스레드가 깨어나지 않아 생산자 스레드가 더 많이 생산 하지 않으며 교착 상태가 발생합니다.
당신이 문제를 이해하면,이 솔루션은 분명하다 : 사용 synchronized
확인하는 notify
사이에 호출되지 않습니다 isEmpty
및 wait
.
세부 사항으로 이동하지 않고이 동기화 문제는 보편적입니다. Michael Borgwardt가 지적했듯이 대기 / 알림은 스레드 간의 통신에 관한 것이므로 항상 위에서 설명한 것과 유사한 경쟁 조건으로 끝납니다. 이것이 "동기화 된 내부 대기"규칙이 적용되는 이유입니다.
@Willie가 게시 한 링크 의 단락은 다음과 같이 요약합니다.
웨이터와 알리미가 술어 상태에 대해 동의한다는 절대적인 보증이 필요합니다. 웨이터는 잠들기 전에 어느 시점에서 술어의 상태를 약간 점검하지만, 잠자기 상태에있을 때 술어의 정확성에 달려 있습니다. 이 두 이벤트 사이에 취약점이있어 프로그램을 중단시킬 수 있습니다.
생산자와 소비자가 동의해야하는 조건은 위의 예에 buffer.isEmpty()
있습니다. 대기 및 알림이 synchronized
블록 단위 로 수행되도록하여 계약이 해결됩니다 .
이 게시물은 다음 기사로 다시 작성되었습니다. Java : 동기화 된 블록에서 대기를 호출해야하는 이유