2014-11-24 77 views
2

我不明白爲什麼沒有線程永遠不會進入方法等書面synchronized方法的Java

public class File { 

    private boolean writing = false; 

    public synchronized void write() 
    { 
     String name = Thread.currentThread().getName(); 
     while(this.writing == true){ 
      System.out.println(name +" wait "); 
      try { 
       this.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     this.writing=true; 
     System.out.println(name +" writing "); 
     try{ 
      Thread.sleep((int)(Math.random()*3000)); 
     } catch(InterruptedException e){ 
      e.printStackTrace(); 
     } 
     this.writing=false; 
     System.out.println(name +" writing end "); 
     this.notifyAll(); 
    } 
} 

public class M_thread extends Thread{ 
    File file; 

    public M_thread(String name,File f){ 
     super(name); 
     this.file=f; 
    } 

    public void run(){ 
     while(true){ 
      file.write(); 
     } 
    } 
} 


public class Main { 

    public static void main(String[] args) { 
     File file=new File(); 
     new M_thread("t1",file).start(); 
     new M_thread("t2",file).start(); 
     new M_thread("t3",file).start();  
    } 
} 

在我的代碼,我可以防止因睡眠編寫的模擬方法飢餓的問題呢?因爲如果一個線程進入睡眠很長一段時間總是永遠不會超過一個,你把睡覺的時間很短

+0

我錯了,你應該換真的假,但它只是一個後勤錯誤代碼java應該更正 – alexander 2014-11-24 20:56:05

+2

請編輯您的問題,以反映這一點。 – 2014-11-24 20:57:56

+0

是的,當然..我有添加它。 – alexander 2014-11-24 21:20:55

回答

2

I can not understand why no thread never enters into the method wait好寫,這是比較容易來形容:

public synchronized void write() { 
    // ... 
} 

這是一樣的:

public void write() { 
    synchronized(this) { 
     // ... 
    } 
} 

這意味着,只有一個與鎖this線程可以進入這個塊。由於您使用的File相同的實例:

File file=new File(); 
new M_thread("t1",file).start(); 
new M_thread("t2",file).start(); 
new M_thread("t3",file).start(); 

..每個線程都有上this相同的對象引用。因此,如果一個線程進入方法write,那麼另一個線程必須等到這個線程釋放鎖this。 而且由於writing的默認值爲false(並且如果一個線程離開write方法,該值將重置爲false),因此永遠不會輸入循環while(this.writing == true)

1

您對同步的理解有點偏離,它比您想象的要簡單。

由於它是​​,您的線程將不會同時在write()中。所以,你所擁有的無關等待/通知邏輯都是必需的。 this.writing永遠write()開始是真實的,因爲你把它設置爲false,只是每次離開之前write(),由於write()是​​,沒有線程反正「跳」到它的中間。也就是說,在那個時期this.writing爲真的時候,沒有線程會執行write()

你可以擺脫所有的邏輯。這是不夠的,因爲​​已經這樣做對你的工作:

public synchronized void write() 
{ 
    String name = Thread.currentThread().getName(); 
    System.out.println(name +" writing "); 
    Thread.sleep((int)(Math.random()*3000)); 
    System.out.println(name +" writing end "); 
} 

剛剛宣佈write()作爲​​就已經引起調用write()等待輪到他們的其他線程。

注意,在你的榜樣你sleep()調用不會拋出InterruptedException,因爲你永遠不會調用interrupt()interruptions do not come out of nowhere)。爲了簡單起見,我忽略了這個異常處理程序。也就是說,如果你正在構建在其他情況下使用的代碼,那麼將它作爲interrupt()是安全的,因爲你永遠不知道你的代碼將來會如何使用(有人可能會在上下文中使用它)他們期望interrupt()工作)。