2016-10-25 9 views
2

멀티 스레드 시나리오에서 Deadlock을 설명하는 Oracle의 Java 자습서에서이 example을 발견했습니다. System.out.format 및 System.out.println을 이용한 스레딩

그래서이 예제에서 나는

Alphonse: Gaston has bowed to me! 
Gaston: Alphonse has bowed back to me! 
Gaston: Alphonse has bowed to me! 
Alphonse: Gaston has bowed back to me! 

그래서 출력 다음 줄 17에서 변화와 이러한 변화를 교착 상태를 발생시키지 않고 성공적으로 종료 프로그램을 수행하면 라인 (18)

public class DeadLock { 
    static class Friend { 
    private final String name; 

    public Friend(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return this.name; 
    } 

    public synchronized void bow(Friend bower) { 
     //My Changes 
     //System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName()); //Line 17 
     System.out.println(this.name + ": " + bower.getName() + " has bowed to me!"); //Line 18 
     bower.bowBack(this); 
    } 

    public synchronized void bowBack(Friend bower) { 
     System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName()); 
    } 
    } 

    public static void main(String[] args) { 
    final Friend alphonse = new Friend("Alphonse"); 
    final Friend gaston = new Friend("Gaston"); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      alphonse.bow(gaston); 
     } 
    }).start(); 

    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      gaston.bow(alphonse); 
     } 
    }).start(); 
    } 
} 

다음 제작 및 인쇄 내 질문 - 왜 이런 행동을 했습니까? println 문은 교착 상태를 어떻게 막았습니까?

+0

어떻게 될지 모르겠습니다. 'System.out.format'은 잠금과 관련하여'System.out.println'과 다른 것을 실제로하지 않습니다. –

+2

아무런 차이가 없습니다. 스레드 인터리빙에 따라 교착 상태가 달라 지므로 실행간에 차이가납니다. System.format을 사용하여 여러 번 실행하면 때때로 정확한 결과를 볼 수 있습니다. 그리고 println을 사용하면 프로그램이 교착 상태에있는 곳에서도 실행을 볼 수 있습니다. – assylias

+0

사실 : 첫 번째 변종은 [ideone에서 잘 돌아갈 수 있습니다] (http://ideone.com/bV6nd8). –

답변

5

System.out.print 또는 System.out.format 중 어느 것을 사용하는지에 차이가 없습니다. 기본적으로 동일한 작업을 수행하고 있습니다. Gaston.bow(Alphonse)의 실행이 Alphonse.bow(Gaston)bower.bowBack(Alphonse) (또는 그 반대)의 시작 사이에 시작되는 경우

교착 여기 발생 : 두 개의 스레드가 다른 보유 모니터를 기다리고있다, 따라서 교착 상태가 발생합니다. 교착 상태가없는 것 같습니다 그래서, Gaston.bow 전에 Alphonse.bow하고 완전한 bower.backBack(Alphonse)가 실행되는 것이 가능하다 -는 스레드가 예약 방법에 따라 미묘한 타이밍 문제에 달려 있기 때문에

이는 일관성이 발생합니다.

이 문제를 해결하는 일반적인 방법은 잠금 획득을 주문하는 것이므로 처음에는 동일한 잠금이 처음부터 획득됩니다. 이 교착 상태의 가능성을 방지 :

public void bow(Friend bower) { // Method no longer synchronized. 
    int firstHash = System.identityHashCode(this); 
    int secondHash = System.identityHashCode(bower); 

    Object firstMonitor = firstHash < secondHash ? this : bower; 
    Object secondMonitor = firstHash < secondHash ? bower : this; 
    synchronized (firstMonitor) { 
    synchronized (secondMonitor) { 
     // Code free (*) of deadlocks, with respect to this and bower at least. 
    } 
    } 
} 

(*) 그것은 아니에요을 매우System.identityHashCode는 다른 오브젝트에 대해 동일한 값을 반환 할 수 있기 때문에, 무료 교착 보장; 그러나 그것은 합리적으로있을 법하지 않습니다.

Birthday paradox의 응용 프로그램입니다. 두 개의 모니터 만있는 경우 충돌 가능성은 10^-18과 같습니다. 77k 모니터 이상인 경우 충돌이 발생할 가능성이 큽니다.

4

여기에있는 것들을 혼합합니다.

각 교착 상태와 그 코드가 실행되는 시간을받을 수 코드 의 조각이 반드시 의미하지 않는 교착 상태 상황으로 이어질 수 있다는 사실.

이것은 멀티 스레드와 같은 어려운 주제를 만드는 측면 중 하나입니다. 코드를 한 번 또는 10 번 또는 100 번 실행하고 모든 것이 "작동"하는 경우; 그것은 다음 번에 실패 할 가능성이 여전히 있습니다.

다른 말로하면 : 가장 바깥 쪽 수준의 루프에 코드를 넣으십시오. 조만간 (아마 "빨리"자고 많이하지 않으면) 교착 상태에 빠지게됩니다!

가지

1

교착 상태가에 따라 ... 쉽고 교착 상태가 쉽게 우리가 모든 책과 도서관과 방법 멀티 스레딩을 처리하는 아이디어를 필요로하지 않을 것이라고 감지 할 수 아니라고한다면 println 함수. 두 스레드가 서로 액세스하고 서로를 잠금으로써 발생합니다.

format에서 println으로 변경하면 스레드가 충돌 (예 : 교착 상태)없이 서로 잠글 수 있도록 프로그램에 충분한 대기 시간이 도입됩니다. 그래서 당신은 그것을 고쳐주지 않았습니다; 방금 스레드가 교착 상태가 아니라는 것을 의미하는 대기 시간을 추가했습니다.

3

실제 증거로 나머지 답변을 지원하려면 코드를 루프에서 실행하고 100 회 시도 중 82 번 교착 상태가 발생하여 코드가 여전히 교착 상태에 빠지게됩니다.

+0

나는 그것에 동의하지 않는다. 문제는 "println 문이 교착 상태를 어떻게 막았습니까?"입니다. 내 대답은 그렇지 않다는 것입니다. 나는 그것이 다른 답변을 참조하기 때문에 그것이 스스로 응답으로 서 있지 않는다는 것에 동의 할 수있다. – Raniz

+0

의미가있다 ;-) – GhostCat