2012-02-21 2 views
9

나는 알퐁스가 두 스레드가 동기화 된 메서드에 동시에 액세스 할 수 있습니까?

로 출력을 얻고이 프로그램을 실행
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) { 
      System.out.format("%s: %s" 
       + " has bowed to me!%n", 
       this.name, bower.getName()); 
      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() { 
      public void run() { alphonse.bow(gaston); } 
     }).start(); 
     new Thread(new Runnable() { 
      public void run() { gaston.bow(alphonse); } 
     }).start(); 
    } 
} 
: 가스통이 나에게 절을했습니다! 가스통 : Alphonse가 나에게 절을했습니다!

그래서 두 스레드가 동기화 된 메소드에 동시에 액세스 할 수 있습니까?

+0

가능한 복제본 [쓰레드가 교착 상태에 빠지는 것을 방지하기 위해 노력하고 있습니다] (http://stackoverflow.com/questions/749641/trying-to-wrap-my-wee-brain-around-how-threads-deadlock) –

답변

7

두 스레드가 동기화 된 메소드에 동시에 액세스 할 수 있습니까?

예제와 같은 인스턴스 메서드는 해당 메서드가 포함 된 개체에서 동기화됩니다. 이 경우 alphonse.bow(...)으로 전화하면 alphonse 개체가 잠겨 있습니다. gaston.bow(...) 자물쇠 gaston.

개체의 여러 인스턴스를 동일한 개체에서 잠글 수있는 방법은 여러 가지가 있습니다.

    당신은 방법 staticsynchronized이있는 경우가 클래스 객체 자체에 고정 할 수 만들 수
  • . 클래스 로더 당 이러한 객체 중 하나만 있습니다.

    public static synchronized void bow(Friend bower) { 
    
  • 정의 된 정적 개체에서 모두 잠글 수 있습니다. 다음과 같이하십시오 :

    private static final Object lockObject = new Object(); 
    ... 
    public void bow(Friend bower) { 
        synchronized (lockObject) { 
         .... 
        } 
    } 
    
    2 또는 정적으로 설정하지 않으려면 개체를 전달할 수 있습니다.

귀하의 출력은 같은 수 다음 Gaston: Alphonse has bowed to me!

  • :

    1. gaston 실이가 gaston 객체와 출력을 고정 bow(alphonse)
    2. 처음 시작하고 호출 (수) 전화는 alphonse.bowBack(this)입니다. Alphonse: Gaston has bowed back to me!
    3. alphonse.bowBack(this) 이탈 상기 alphonse 객체를 해제 :
    4. 이 호출은 alphonse 객체를 출력을 잠근다.
    5. gaston.bow(alphonse)이 종료되면 gaston 개체가 잠금 해제됩니다.
    6. 그러면 gaston 스레드가 종료됩니다.
    7. alphonse 다음 스레드를 시작 (할 수있다)와 bow(gaston)
    8. 이것은 alphonse 객체를 출력 잠금 호출 Alphonse: Gaston has bowed to me!
    9. gaston.bowBack(this)를 호출한다. Gaston: Alphonse has bowed back to me!
    10. gaston.bowBack(this) 이탈 상기 gaston 객체를 해제 :
    11. 이 호출은 gaston 객체를 출력을 잠근다.
    12. alphonse.bow(gaston)alphonse 개체를 잠금 해제합니다.

    이것은 여러 가지 주문에서 발생할 수 있습니다. 나중에 start() 메서드가 호출 되더라도 alphonse 스레드가 먼저 실행될 수 있습니다. 자물쇠가 당신을 구할 수있는 유일한 방법은 alphonse.bowBack(...)이 현재 실행중인 경우 alphonse.bow(...)의 호출입니다. @ user988052가 지적했듯이 각 스레드는 자신의 개체를 잠근 다음 다른 스레드를 잠그려고하기 때문에 쉽게 교착 상태가 발생할 수 있습니다.

  • +0

    좋아 ..하지만 때로는 내가이 프로그램을 실행하면 출력을 얻을 : 가스통 : Alphonse 나에게 절을했습니다! Alphonse : 개 스톤이 나에게 다시 물러 섰다! Alphonse : 가스통이 절 썰렁 해졌습니다! 가스통 : Alphonse가 나에게 물러 섰다! 그럼 .. 어떻게됩니까?이 프로그램은 튜토리얼 에서처럼 차단해야합니다. – harish

    +0

    @harish : 두 번째 스레드가 시작되기 전에 첫 번째 스레드가 작업을 완료했을 수 있기 때문에 발생합니다. 그래서 (적어도 아주 좋은 가능성으로) 교착 상태를 확실히 만드는 이유는 많은 스레드를 인스턴스화해야한다는 것입니다 (내 대답 참조). – TacticalCoder

    +0

    @ user988052 나중에 알겠습니다. 고마워요. – harish

    10

    두 스레드가 동기화 된 메소드에 동시에 액세스 할 수 있습니까?

    예와 아니오 :

    • 예, 방법은 클래스의 다른 인스턴스에서 호출되는 경우.

    • 아니요, 두 스레드가 에서 동기화 된 메서드를 동시에 호출 할 수 없습니다. 동일한 인스턴스입니다. 두 스레드가 서로 다른 메소드를 호출하는 경우에도 마찬가지입니다 (인스턴스가 동일하면).

    +2

    주 : 동기화 된 메소드가 동일한 오브젝트에 대해 다른 동기화 된 메소드를 호출하면 하나의 스레드가 동일한 오브젝트의 두 동기화 된 메소드에 동시에있을 수 있습니다. –

    +0

    @aix - 답변을 수정하여 수업에서 동기화가 완료되었음을 나타낼 수 있습니까? 또한 첫 번째 글 머리 기호가 클래스 동기화에 맞지 않습니다. – Perception

    +0

    @Perception : 내가 따를 지 모르겠다. 메소드가 '정적'이 아니므로 동기화는 클래스가 아닌 인스턴스를 잠급니다. 무슨 뜻인지 설명해 주시겠습니까? – NPE

    0

    synchronized 키워드를 사용하면 인스턴스 메소드의 인스턴스 또는 정적 메소드의 클래스를 잠글 수 있습니다. 그래서 당신은 하나의 쓰레드가 활이나 보우를 실행한다는 것을 보증합니다 주어진 시간에 주어진 인스턴스에 대한 백업을 수행합니다 (하나의 쓰레드가 활을 실행하면 다른 쓰레드는 bowBack을 실행할 수 있습니다) ...

    하나 more comment : 잠금이 재진입 성 (reentrant)이므로 일단 스레드가 잠금을 획득하면 동일한 잠금에서 동기화하는 다른 메소드를 입력 할 수 있습니다.

    1

    Deadlock Tutorials에 설명되어 있으며,이 코드는에서 오는 코드이며, 일반적으로이 코드는 차단됩니다.

    교착 상태가 실행되면 bowBack을 호출 할 때 두 스레드가 모두 차단 될 가능성이 큽니다. 각 스레드는 다른 스레드가 활을 벗어날 때까지 기다리고 있기 때문에 어느 블록도 종료되지 않습니다.

    2

    나는 자세히 코드를 확인하지 않았지만 내가 교착 상태를 만드는 방법에 관한 전형적인 예를 인식 생각합니다.

    그러나 교착 상태를 만들려고 한 번만 호출하면 안됩니다.

    루프에서 스레드를 생성하고 당신이 당신의 교착 상태거야 매우 ​​높은 가능성이있다 : 당신이 당신의 2000 스레드 교착하지 않습니다

    for (int i = 0; i < 1000; i++) { 
        final Friend alphonse = 
         new Friend("Alphonse"); 
        final Friend gaston = 
         new Friend("Gaston"); 
        new Thread(new Runnable() { 
         public void run() { alphonse.bow(gaston); } 
        }).start(); 
        new Thread(new Runnable() { 
         public void run() { gaston.bow(alphonse); } 
        }).start(); 
    } 
    

    참고 : 그들 중 일부는 교착 될 것이다. 당신은 당신의 프로그램/JVM의 threadump를 취함으로써이를 검증 할 수있다.

    관련 문제