2012-09-16 66 views
1

我發現在經典Java Deadlock Tutorial中包含對System.out.format的調用將防止發生死鎖,並且我找不到原因。System.out.format如何防止死鎖?

下面的代碼是相同的教程,與除mainSystem.out.format("Hi, I'm %s...no deadlock for you!\n\n", alphonse.getName());

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) throws InterruptedException { 
     final Friend alphonse = new Friend("Alphonse"); 
     final Friend gaston = new Friend("Gaston"); 

     System.out.format("Hi, I'm %s...no deadlock for you!\n\n", alphonse.getName()); 

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

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

這裏的輸出:

Hi, I'm Alphonse...no deadlock for you! 

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! 

卸下以通常的死鎖問題的行結果:

Alphonse: Gaston has bowed to me! 
Gaston: Alphonse has bowed to me! 
... deadlock ... 

是否是對System.out的調用。格式以某種方式改變線程獲取對象的內部鎖的方式?

更新:

我能得到系統只是通過改變再次陷入僵局,我的代碼啓動線程:

public static void main(String[] args) throws InterruptedException { 
    final Friend alphonse = new Friend("Alphonse"); 
    final Friend gaston = new Friend("Gaston"); 

    System.out.format("Hi, I'm %s...no deadlock for you!\n\n", alphonse.getName()); 

    Thread t1 = new Thread(new Runnable() { 
     public void run() { alphonse.bow(gaston); } 
    }); 

    Thread t2 = new Thread(new Runnable() { 
     public void run() { gaston.bow(alphonse); } 
    }); 

    t1.start(); 
    t2.start(); 
} 

這就引出了我們如何能夠得到更深入的瞭解這個問題進入線程調度程序的行爲方式,但我會在不同的一天保存它。

+0

當您添加該行時,第一個線程在主線程啓動第二個線程之前完成。 –

+0

但是,這只是巧合在一個特定的處理器和調度程序。仍然不能保證不會發生死鎖。 – Wyzard

回答

5

你並沒有真正刪除僵局而是(因爲內部的一些JVM原因)改變,其他電話bow()線程的時間,使一個線程進入bowBack()之前。 只要在bowsleep(1000)和您的死鎖將重新出現。

請注意,死鎖不會總是發生,只有當線程在幸運時間。在這種情況下,當兩個線程進入bow僵局會發生,並呼籲bowBack

... 而「一些內部JVM原因」之前任何一個可以是以下:

你的情況有實際上有三個線程:執行主體主體,t1t2。 之所以把打印隱藏了死鎖是線程調度程序決定main仍然有工作要做,即刷新IO緩衝區,因此讓開始T1之後和在開始t2以前主要繼續。如果您使用的是雙核cpu,則只有maint1會運行,但t2會等待,因爲print是慢速操作。上下文切換會花費更多時間,並且t1會在t2之前完成,可能會啓動...因此不會發生死鎖。但這並不意味着如果你再次運行程序,死鎖就不會發生。

如果您想玩,請創建一個queue並在該隊列中推送令牌(線程名稱),然後在您的主線程中使用join線程。完成後,打印隊列內容,您可以觀察線程的時間。

0

format()並且寫入控制檯通常是費用較高的操作。我猜想它的執行正在改變線程啓動的時間,因此第二個線程開始的時間太晚,以至於不會影響第一個線程。