2012-05-12 62 views
3

鑑於這種Java代碼:此多線程Java代碼如何工作?

class Account { 
     private Integer number = 0; 
     public synchronized void setNumber(Integer number) { 
      this.number = number; 
     } 

     public synchronized Integer getNumber() { 
      return number; 
     } 
    } 

    class Client extends Thread { 
     Account account; 
     public Client(Account account) { 
      this.account = account; 
     } 
     public void run() { 
      for (int i = 1; i <= 1000; i++) { 
      account.setNumber(account.getNumber() + 1); 
      } 
     } 
    } 

    public class Run { 
     public static void main(String[] args) throws Exception { 
      Account account = new Account(); 
      Client one = new Client(account); 
      Client two = new Client(account); 
      one.start(); 
      two.start(); 
      one.join(); 
      two.join(); 
      System.out.println("Exiting main"); 
     System.out.println("account number value: " +account.getNumber());   
     } 
    } 

什麼是number當主方法完成的價值?是2000還是2000以下?我低於2000.兩個線程如何同時從run()調用getNumer()setNumber(),因爲每個線程都是同步的?

回答

8

仔細想想下一節會發生什麼。

account.setNumber(account.getNumber() + 1); 

即使這兩種方法是分開同步的,整個操作都不是。

+0

感謝RajChola回答 – Vijay

+0

你」歡迎。如果你對你的問題有一個答案,你應該選擇其中一個答案是正確的。 – Sridhar

5

該數字可能小於或等於2000,但從不更高。考慮每個「設置」和「獲取」號碼功能分別同步但它們不同步在一起。這意味着線程之間的爭用條件有可能將「跳過」調用組合爲「增量」效果。

考慮調用這個可能的序列兩個線程之間:

number Thread1  Thread2 
0  get => 0 - 
-  -   get => 0 
-  -   incr => 1 
1  -   set => 1 
-  incr => 1 - 
1  set => 1 - 

注意,每個線程拿到了多少個零,分別遞增,然後設置的頭號。兩個主題都認爲他們增加了數字,但他們對set/get的調用是交錯的,所以其中一個被有效地跳過了。

對比,嘗試寫在名爲increment()它執行GET /增量Account類第三同步方法/設置序列原子,看到你總是會得到數2000

+0

謝謝Maerics回答我的問題 – Vijay

+0

+1。好的例證。 – SiB