2016-09-07 40 views
0

對於我的編程語言類,我們給了一個簡單的Java死鎖例子,並被要求解決它。我不直接想要這個問題的答案,我主要想知道我的理解缺乏的地方。下面的代碼:請幫我理解這個死鎖的例子

import java.applet.*; 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 

// Attempt at a simple handshake. Girl pings Boy, gets confirmation. 
// Then Boy pings girl, get confirmation. 
class Monitor { 
    String name; 

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

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

    // Girl thread invokes ping, asks Boy to confirm. But Boy invokes ping, 
    // and asks Girl to confirm. Neither Boy nor Girl can give time to their 
    // confirm call because they are stuck in ping. Hence the handshake 
    // cannot be completed. 
    public synchronized void ping (Monitor p) { 
     System.out.println(this.name + " (ping): pinging " + p.getName()); 
     p.confirm(this); 
     System.out.println(this.name + " (ping): got confirmation"); 
    } 

    public synchronized void confirm (Monitor p) { 
     System.out.println(this.name+" (confirm): confirm to "+p.getName()); 
    } 
} 

class Runner extends Thread { 
    Monitor m1, m2; 

    public Runner (Monitor m1, Monitor m2) { 
     this.m1 = m1; 
     this.m2 = m2; 
    } 

    public void run() { 
     //System.out.println(m1.getName() + " about to ping " + m2.getName()); 
     m1.ping(m2); 
    } 
} 

public class DeadLock { 
    public static void main (String args[]) { 
     int i=1; 
     System.out.println("Starting..."+(i++)); 
     Monitor a = new Monitor("Girl"); 
     Monitor b = new Monitor("Boy"); 
     (new Runner(a, b)).start(); 
     (new Runner(b, a)).start(); 
    } 
} 

當我執行上面的代碼,我相信下面的應該發生的每一次(儘管它沒有,因爲有時候我們死鎖):

女孩坪男孩,在把鎖方法ping()。女孩,在ping()內,試圖撥打boy.confirm()。男孩的confirm()的答案,從而使我們回到Girl.ping()它完成,取消關閉ping(),和男孩的例子做的完全一樣的事情。有了所有的鎖,看起來整個程序是序列化的,雖然這樣就打破了多線程的目的?無論如何,我通常會得到下面的輸出

Starting...1 
Girl (ping): pinging Boy 
Boy (confirm): confirm to Girl 
Girl (ping): got confirmation 
Boy (ping): pinging Girl 
Girl (confirm): confirm to Boy 
Boy (ping): got confirmation 

但是有時我們得到了一個僵局,輸出變爲:

Girl (ping): pinging Boy 
Boy (ping): pinging Girl 

我不明白,我們怎麼能在這種狀態下獲得,雖然,因爲它似乎當我們第一次進入時,我們鎖定了ping()方法,那麼如果女孩已經在使用它,男孩甚至會打電話給ping()?當男孩正忙着打電話給ping()時,女孩試圖撥打boy.confirm()

+0

你的目標是讓你的程序可序列化。它並沒有打破多線程的目的。當你有一個資源和多個線程時,就不會產生魔法,即多線程不能同時使用資源。 – UmNyobe

回答

5

ping方法是同步的,並呈現this鎖,然後它前進到調用confirmp,從而試圖奪取其鎖定爲好。在以下步驟:

  1. 「女孩」 線程獲取鎖Boy對象,進入ping;
  2. 「男孩」線程獲取鎖定對象Girl,輸入ping;
  3. 女孩想打電話Boy.confirm,等待鎖定;
  4. 男孩想打電話Girl.confirm,等待鎖定;
  5. 僵局。
+0

我不清楚的是,我們獲得了另一個實例的鎖定。謝謝。 –

0
  • 主題1:啓動
  • 線程1:在通話平,坐上監視器,執行System.out.println打印 女孩(平):查驗男孩
  • 線程1:搶佔由VM
  • 主題2:啓動
  • 線程2:b上調用平,得到b上監視器,執行System.out.println打印男孩 (平):查驗女孩
  • 線程2:調用A.確認,等待監視器上一個
  • 主題1:簡歷
  • 線程1:調用b.confirm,等待監視器b上
  • 線程1和2,現在對資源等待另一個線程是 控股。死鎖

這裏的事情是,public synchronized void ping (Monitor p)意味着在類的實例一個顯示器。兩個不同的實例在到達關鍵部分時將完全無關。

通過不同線程獲取不同順序的同步機制時,經常發生死鎖。爲了解決這個問題(行使的範圍內),有兩種可能性:

  1. 同步的類的實例,這是激進

    public void ping (Monitor p) { 
        synchronized(Monitor.class) { 
    
        } 
    } 
    
  2. 明確顯示同步秩序,這是詳細和\或容易出錯。例如

    class Runner extends Thread { 
        Monitor m1, m2; 
        bool m1_first; 
        public Runner (Monitor m1, Monitor m2, bool sync_m1_first) { 
         this.m1 = m1; 
         this.m1 = m2; 
         m1_first = sync_m1_first; 
        } 
    
        public void run() { 
    
         if(m1_first) 
         { 
          synchronized(m1) { 
           synchronized(m2) { 
            m1.ping(m2); 
           } 
          } 
         } 
         else 
         { 
          synchronized(m2) { 
           synchronized(m1) { 
            m1.ping(m2); 
           } 
          } 
         } 
        } 
    } 
    ... 
    (new Runner(a, b, true)).start(); 
    (new Runner(b, a, false)).start();