2009-12-17 5 views
3

나는 .NET 세계에서 왔으며 불행히도 Java 소스를 .NET 님의 눈으로보고 있습니다.Java 동기화 게임 : 동기화 && 대기 && 알림

다음 코드는 안드로이드 앱에서 (안 안드로이드 특정 전혀하지만)입니다 :

private class Worker implements Runnable { 
     private final Object mLock = new Object(); 
     private Looper mLooper; 

     Worker(String name) { 
      Thread t = new Thread(null, this, name); 
      t.start(); 
      synchronized (mLock) { 
       while (mLooper == null) { 
        try { 
         mLock.wait(); 
        } catch (InterruptedException ex) { 
        } 
       } 
      } 
     } 

     public Looper getLooper() { 
      return mLooper; 
     } 

     public void run() { 
      synchronized (mLock) { 
       Looper.prepare(); 
       mLooper = Looper.myLooper(); 
       mLock.notifyAll(); 
      } 
      Looper.loop(); 
     } 

     public void quit() { 
      mLooper.quit(); 
     } 
    } 

내가 어떻게 synchronized 작품에 정확하게 명확하지 않다. 처음에는 synchronized가 mLock 객체를 잠그고 있다고 생각했지만, t.start() 생성자 스레드가 먼저 sync 블록에 들어가면 mLock.wait()에서이를 차단하고 synchronized 블록을 입력하는 것을 차단하여 스레드 "t"를 암시 적으로 차단합니다. 내 휴대 전화 고리가

다음 생각은 동기화가 "코드 블록"(이 경우, 두 개의 동기화 된 블록은 두 개의 서로 다른 동기를 입력 할 수있는 독립적 인 => 스레드가 동기화입니다 :) 생각으로하기 때문에

이것은 분명히 잘못된 것입니다 제한없이 동시에 차단).

... 내 동료가 mLock.wait()이 mLock을 잠그고 다른 스레드가 mLock에서 중요한 부분을 동시에 입력 할 수 있다고 말을들을 때까지.

내가 충분히 명확한 지 확실하지 않으므로 이에 대한 질문에 기꺼이 답변 해 드리겠습니다.

+0

첫 번째 질문 : 귀하의 궁금한 점은 무엇입니까? – erickson

+0

이 코드는 어떻게 작동합니까? :) – Jox

답변

8

Object.wait()에서 javadoc을 확인하십시오. synchronized() 블록을 입력 할 때 얻은 모니터를 삭제한다는 것은 "마법"입니다. 그러면 다른 스레드가 모니터를 가져와 Object.notify()으로 호출 할 수 있습니다.

wait() 호출에서 대기중인 스레드를 깨우기 위해 다른 스레드가 notify()를 호출하면 대기중인 스레드는 모니터를 다시 획득하고 가능한 한 차단합니다. wait() 호출. 그리고 통지 스레드는 새롭게 대기중인 대기 스레드가 진행될 수 있기 전에 동기화 된 블록을 완료합니다. 모든 것이 예측 가능하게 배열됩니다.

+1

이것은 사실 자바의 동기화를 이해하는 데 중요한 요소입니다. 잠깐만 기다리면 잠금이 해제됩니다. 내가 그것을 완전히 이해하자마자 모든 것이 결정적으로되었습니다. – Bombe

+0

OK ... 이제 더 명확 해졌습니다 :) 또 하나의 질문 : 예를 들어 run()의 sync 블록에서 'mLock.notifyAll()'행 다음에 행이 더 많이 있다고 가정 해 봅시다. 모두 올바르게 이해했다면 생성자의 스레드는 run()의 notifyAll 바로 다음에 코드가 실행되지 않고 run()의 스레드가 sync 블록을 종료 한 후에 만 ​​계속 진행됩니까? – Jox

+2

notify() javadoc에서 언급했듯이 notify() 호출자는 모니터가 정상적으로 종료 될 때까지 (동기화 된 블록 또는 다른 것으로 끝나는) 모니터를 해제하지 않습니다. 따라서 새로 잠에서 깨진 wait() 스레드는 모니터를 다시 획득 할 수있을 때까지 차단됩니다. 그것은 notify() 호출자가 그것을 해제 할 때까지는 일어나지 않습니다. 따라서 동기화 된 블록의 끝 이전에 notify()를 따르는 코드는 다른 스레드가 모니터를 받기 전에 확실히 실행됩니다. –

1

synchronized은 객체 모니터를 사용합니다. 객체에 wait()을 호출하면 객체 모니터가 원자 적으로 해제됩니다. 그렇지 않으면 다른 스레드가 모니터를 가져 와서 웨이터에게 notify을 발행 할 수 없습니다.

1

예. wait() 메서드에 대한 설명을 읽으면 다른 스레드가 notify 또는 notifyAll을 잠글 때까지 스레드가 스레드를 잠금 해제하고 차단한다는 것을 알게됩니다. 현재 스레드는 잠금을 다시 획득 할 수있을 때까지 대기하고 일단 수행하면 잠금을 계속 실행합니다.

표시된 코드는 완전히 빌드되기 전에 Worker 인스턴스가 "게시"(즉, 다른 스레드가 개체에 액세스 할 수있게 만들기 때문에)하기 때문에 좋지 않은 방법입니다. 이 방법에서 추가 장벽을 사용하면 클래스의 특성과 결합하여이 경우를 안전하게 만들 수 있지만 일반적으로 그렇지 않습니다.

0

설명해 드리죠 :

생성자는 run() 메소드를 실행하는 새로운 스레드를 시작합니다. 이 새 스레드는 새로운 Looper 객체를 가져 와서 mLooper 필드에 저장 한 다음 Looper 메시지 루프를 실행합니다. 그 사이에 mLooper가 설정된 첫 번째 스레드에 알립니다().

따라서 첫 번째 스레드는 mLooper가 설정된 후에 만 ​​생성자에서 반환됩니다. 즉, 두 번째 스레드에서 Looper.loop() 처리가 곧 시작되거나 이미 시작된 것입니다.