2012-01-27 6 views
6

결코 멈추지 않아야하는 테스트 앱을 작성했습니다. t.wait() (tThread 개체 임)을 발행하지만 알림을 요청하지 않습니다. 왜이 코드가 끝날까요? t에서 동기화되는 주 스레드에도 불구하고 생성 된 스레드가 실행되므로이 ​​개체를 잠그지 않습니다.Java는 대기중인 스레드에 암시 적으로 통지합니까?

public class ThreadWait { 
    public static void main(String sArgs[]) throws InterruptedException { 
     System.out.println("hello"); 
     Thread t = new MyThread(); 
     synchronized (t) { 
      t.start(); 
      Thread.sleep(5000); 
      t.wait(); 
      java.lang.System.out.println("main done"); 
     } 
    } 
} 

class MyThread extends Thread { 
    public void run() { 
     for (int i = 1; i <= 5; i++) { 
      java.lang.System.out.println("" + i); 
      try { 
       Thread.sleep(500); 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 
} 

그 결과 메인 스레드가 5 초 동안 대기하고이 시간 동안 작업자가 출력을 제공합니다. 그런 다음 5 초가 끝나면 프로그램이 종료됩니다. t.wait() 기다리지 않습니다. 주 스레드가 5 초 동안 잠을 자지 않으면 (이 줄 주석 처리), t.wait()은 실제로 작업자가 완료 될 때까지 대기합니다. 물론 join()은 여기에서 사용하는 방법이지만, 예기치 않게 wait()join()과 동일한 작업을 수행합니다. 왜?

아마도 JVM에서는 하나의 스레드 만 실행 중이기 때문에 주 스레드에 알릴 기회가 없으며 교착 상태를 해결할 수도 있습니다. 이것이 사실이라면 문서화 된 기능입니까? 나는 Windows XP에서 테스트하고 있습니다

,

+0

1 초 또는 2 초만 자면 어떻게됩니까? 그렇다면 주 스레드가 스레드 t가 실행을 끝내기를 기다릴 것입니다. – Renato

답변

9

당신은 Thread에 기다리고있어 - 그리고 스레드가 종료 될 때이 암시 적으로 통보하지 대부분의 개체가하는 Thread 객체가 통지된다. 그것은 어딘가에 (내가 찾고 있어요 ...) 이 아니라wait/notifyThread 개체가 내부적으로 사용되어야합니다.

이것은 동기화 (및 대기/알림)에 "개인"개체를 사용하는 가장 좋은 방법입니다. 코드 만 알고 있습니다. .

private final Object lock = new Object(); 

(그러나 일반적으로, 당신이 할 수있는 경우 의견에서 언급 한 바와 같이 java.util.concurrent의가 제공하는 높은 수준의 추상화의 일부를 사용하는 청소기, 그것은 또한 좋은 : 나는 보통 같은 것을 사용 Thread을 확장하는 대신 Runnable을 구현하는 것이 좋습니다.)

+0

스레드의 여러 메소드가 해당 객체에서 동기화되고 wait/notify를 사용하므로 가짜 깨우기가 필요합니다. 스레드를 확장하지 않고 스레드로 래핑 된 Runnable을 사용하는 것도 좋은 습관입니다. 이것은 또한이 문제를 피할 수 있습니다. –

+1

@PeterLawrey : OP가 스레드에서가 아니라 실행 가능 파일에 대기/알림을 사용하는 한, 나는 개인적으로 * 어디에도 * 노출시키지 않는 "멍청한"개체를 선호합니다. –

+0

미래에 코드가 어떻게 바뀔지 모르기 때문에 둘 다 원한다는 것이 이상적입니다. IMHO는 모범 사례 인 여러 가지 전략을 사용하여 코드를 더 잘 보호합니다. –

8

waitJavaDoc 자바 6. 답을 제공합니다 : 의사를 깨우는이 가능합니다. 즉, JVM은 언제든지 wait에 대한 호출을 종료 할 수 있습니다.

도큐멘트를 원할 경우 해결책이 될 것입니다 (아마도 항상 그렇습니다). wait에 전화를 걸어 매 순간마다 기다리는 조건이 참이되었는지 확인하십시오.

+3

@ 보리스 가짜 깨우기의 경우 예외는 없습니다. InterruptedException은 스레드가 인터럽트 된 경우에만 발생합니다. –

+2

나는 이것이 실제로 * 가짜 웨이크 업이라고 생각하지 않는다 - 나는 이것이'스레드 '를 기다리는 행동이라고 생각한다; thread가 종료하면 (자) 통지됩니다. 정상적인 의미에서 가짜가 아닙니다. –

+2

가짜 웨이크 업이 없어도 모니터 패턴 (또는 그 변형)을 사용하면 항상 루프를 만들고 조건을 확인하려고합니다. 이렇게하면 나중에 다른 조건을 추가 할 때 문제가 발생하지 않습니다 (Java 및 C# 모니터는 하나의 객체를 잠금 및 조건 변수로 사용하므로 조건 당 하나의 조건 변수를 사용할 수 없습니다). 또한 조건이 충족되었지만 동일한 객체를 기다리고있는 다른 스레드가 먼저 갔다가 이제는 조건이 더 이상 true가 아닌 경우 사용자가 처리하지 못하게합니다. –

관련 문제