[Java][synchronized] wait 와 while


작성자 : 김민석 ( lemonfish at gmail dot com )
어떤 사람으로 부터 질문을 받았다.

"Java API 에 wait 을 쓸때는 while 과 함께 쓰라고 분명히 되있는데 왜 그래야 하냐?"
  라는 것이였다.

그래서 문제가 되는 Java API document 의 한 부분을 발췌한 것이 아래이다. 
이 글은 JDK 5.0 의 API document 에서 발췌한 것인데. 1.4 API document 에는 없는 부분이다. Sun 에서 문서화를 할 때 중점을 두는 부분이 예제의 추가라는 걸 알수 있다.(물론 문서화에는 애매한 부분을 좀더 명확하게 기술하는 부분도 들어간다.)  

Object 클래스의 wait 메서드에 대한 설명중 한부분이다. 개발자들이 어렵게 생각하니 친절하게도 이런 용도로 쓸때는 이런식으로 하면된다. 라는 식으로 예제를 만들어놓았다.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

synchronized (obj) {
while(<condition does not hold>)
    obj.wait(timeout, nanos);
...
// Perform action appropriate to condition
}



결론은 이렇다. 

   세라비 님의 교정을 통해 수정한 내용입니다.

wait 을 걸어놔도 예기치 않게 block 이 깨지는 수가 있으니 wait 해야하는 조건을 while 의 <condition does not hold> 부분에 넣어서 보호하라는 예기다. 물론 wait 해야하는 조건이 아닐경우 while 을 빠져나와 정상수행을 하게 된다.

유명한 예제인 생산자 - 소비자 를 예로 들어 보자.

public synchronized String get(){
  while(bMsg == false){
    //bMsg 는 생산자 또는 소비자가 작업을 완료했음을 알리는 플래그
    try{ wait(); } catch(Exception e){}   
    .... some jobs ...
    return msg;
  }
}

위 코드는 상대의 작업이 완료되었을 때 자신의 처리를 수행하도록 되어있다. 때문에 상대의 작업 완료를 검사하고 작업이 완료되지 않았을 경우 wait 을 통해 대기하게 된다. wait 의 경우 notify 나 notifyAll 을 통해 대기가 해제되는데 문제는 코드상에 나와있지 않은 어떠한 요소(interrupts and spurious wakeups) 로 인해 wait 이 해제될 수 있다는 것이다. 따라서 작업이 완료되었을때 notify 나 notifyAll 을 호출하여 wait 을 해제하도록 하였다 하더라도 확실히 그것이 작업완료로 인한 대기해제인지는 보장이 되지 않는다는 것이다. 때문에 wait 이 해제 되더라도 완료플래그를 반드시 다시 검사하여야 한다. while 은 그러한 조건검사 수행을 위해 사용된다.

by killy | 2008/03/11 19:42 | Java | 트랙백 | 덧글(6)

트랙백 주소 : http://lemonfish.egloos.com/tb/4215696
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 세라비 at 2008/03/14 07:20
wait는 while과 함께 써야합니다. 일반적으로 posix monitor (condition variable) 구현의 wait도 spurious wakeup (signal이 오지 않아도 깨어날 수 있음)이 있기 때문입니다. spurious wakeup이 자주 일어나지는 않지만 loop가 없는 상황에서 발생하면 황당한 동작을 보이게 되죠.
Commented by killy at 2008/03/14 11:51
세라비님 의견 감사합니다. 잘못된 내용을 게시해놓으면 안되는데 큰일날뻔했네요. 내용을 말씀하신것을 토대로 수정했습니다. 감사합니다.
Commented by 원질문자\"어떤사람\" at 2008/03/15 12:24
와우! 굉장히 속시원한 답변이었습니다. 감사합니다. 그런데 또다른 궁금증이 생겼습니다. 만약 wait()을 if문 속에 넣고 notifyAll() 이후의 작업을 else문에 넣으면 어떨까요? 그래도 결과는 마찬가지일 것 같은데 말이죠. if문 조건만족에 의해 waiting하다 notifyAll로 깨어나면 else문은 그냥 넘어가게 되죠. 그리고 이 if문을 포함하는 모체인 메쏘드가 생산자 쓰레드에 의해 또다시 호출될 것이고 다시 if문 검사를 통해 이번에는 else문의 내용을 실행하는 식이죠. 메쏘드를 여러번 반복호출하는 것보다, 한번 호출되어 메모리에 적재된 상태에서 while문 반복을 하는 것이 시스템의 성능에 더 좋아서일까요?
Commented by 원질문자 at 2008/03/15 12:29
하번의 작업을 메쏘드를 빠져나온 다음 다시 호출하는 것이 약간 문제가 있을 것 같은 막연한 느낌이 들긴하네요. 그리고 신호가 오지 않아도깨어날 수 있는 상황은 어떤 것들이 있을까요? 아 너무 질문이 많네요. 감사합니다!
Commented by dinga at 2009/05/13 02:17
좋은 정보 감사드립니다.
복받으세요.^^
Commented by killy at 2009/06/05 22:25
뭘요~ 방문해 주셔서 제가 더 감사하지요~ ^-^

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶


동영상 한판 때리시죠? ^-^
rss

skin by FreeCssTemplates