2011-10-13 41 views
1

我有以下代碼。我期望一個線程完全執行其同步方法,然後允許另一個線程訪問相同的方法。然而,這種情況並非如此。爲什麼這個線程允​​許另一個訪問其同步方法?

public class Threads { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     //Thread Th = new Threads(); 
     Thread th = new Thread (new thread1()); 
     th.start(); 
     Thread th1 = new Thread (new thread1()); 
     th1.start(); 
    } 
} 



class thread1 implements Runnable{ 
    String name = "vimal"; 

    public void run() { 
     System.out.println("Runnable "+this.name); 
     setNAme("Manish"); 

    } 

    public synchronized void setNAme(String name){ 
     try { 
      System.out.println("Thread "+Thread.currentThread().getName()); 
      wait(1000); 
      this.name = name; 
      System.out.println("Name "+this.name); 

     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

我有一個輸出

Runnable vimal 
Thread Thread-0 
Runnable vimal 
Thread Thread-1 
Name Manish 
Name Manish 

什麼用這裏同步,如何讓我的方法完全運行另一個訪問之前?

回答

1

您將不得不刪除呼叫等待(1000)。它看起來像你真正想要的是Thread.sleep(1000),如果你只是想暫停當前線程,這不會釋放任何顯示器的所有權。

從Object.wait()的javadoc。

此方法導致當前線程(稱之爲T)到等待組將其自身在 此對象然後放棄該對象上的任何和所有 同步要求。線T成爲 線程調度目的,禁用和一直處於休眠狀態的四件事情 一個發生的情況:

  • 其他某些線程調用此對象的通知方法和縫線T碰巧被任意地選擇作爲線程是 驚醒。
  • 其他一些線程爲此對象調用notifyAll方法。
  • 一些其他線程中斷線程T.
  • 指定的實時量已過或多或少。但是,如果超時爲零,則實時並不考慮 考慮因素,並且線程只是等待直到通知。

線程T然後從爲該對象設置的等待集中刪除,並且爲線程調度重新啓用 。然後它以通常的方式與其他線程競爭 以在該對象上同步權利;一旦 已獲得對該對象的控制權,則該對象的所有同步聲明都將恢復到狀態 - 即等待方法被調用時的狀態爲 。線程T 然後從調用wait方法返回。因此,在等待方法返回 時,線程T的對象和線程T的同步狀態與調用wait方法時的狀態完全相同。

更新:正如在其他答案中提到的,你沒有在同一個對象上同步。一旦你這樣做了,由於我提到的問題,你仍然會遭受同樣的輸出。你將需要修復兩個你想要的結果。

+2

wait方法真的無關與兩個不同的對象同步。但是,當然如果他只使用一個對象,這也會有問題。 – Gandalf

+0

你是對的,我跳過槍回答那個。當然,這是當同一個對象完成同步時,他會遇到的下一個錯誤。 – Robin

6

​​has no這裏的效果是因爲在這兩種情況下你不在同一個對象上同步。應用於實例方法時,​​關鍵字會導致該方法在this上同步。因此,在每種情況下,您都在thread1的實例上進行同步,並且有兩種。

當您同時在兩個線程中運行相同thread1的實例時,更有趣的測試將會是。在這種情況下,致電wait(1000)是一件非常糟糕的事情,因爲(如文檔所述)它釋放了鎖定this。您想在代碼中使用Thread.sleep(1000)

如果你需要有thread1兩個實例,你需要一些共享對象的同步操作,可能是這樣的:

private static final Object lockObject = new Object(); 

public void setName(String newName) { 
    synchronized(lockObject) { 
     doSetName(newName); 
    } 
} 
0

輸出是否正確,要創建到不共享任何獨立線程數據。因此,兩個線程都以第一個字符串開始,並且在一段時間後,該字符串被更改並打印。

0

您正在創建2個thread1對象。他們每個人都有自己的setNAme方法。同步方法只在對象上同步,而不是類。除非該方法是靜態的。

0

這裏有兩個線程,帶有獨立的名稱變量和獨立監視器,因此每個線程只訪問其自己的成員。如果你想讓線程彼此交互,你必須實現這樣的交互。

0

您正在創建兩個單獨的thread1對象並運行它們。每個線程都有自己的名稱變量副本以及setName函數。讓它們都是靜態的,你會看到同步的效果。

0

您正在鎖定不需要任何同步的對象的兩個不同實例。只有在您處理共享數據時,您才需要同步。我想你的意思是寫一個像下面這樣的測試。

如果你測試這個,你會意識到第二個線程將等待,直到第一個線程完成同步方法。然後取出同步字,你會看到兩個線程同時執行。

公共類SynchronizeTest {

public static void main(String[] args) { 
     Data data = new Data(); 

     Thread task1 = new Thread(new UpdateTask(data)); 
     task1.start(); 
     Thread task2 = new Thread(new UpdateTask(data)); 
     task2.start(); 
    } 
} 
class UpdateTask implements Runnable { 
    private Data data; 

    public UpdateTask(Data data) { 
     this.data = data; 
    } 

    public void run() { 
     try { 
      data.updateData(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

    class Data { 
    public synchronized void updateData() throws InterruptedException { 
     for (int i = 0; i < 5; i++) { 
      Thread.sleep(5000); 
      System.out.println(i); 
     } 
    } 

} 
相關問題