2011-06-22 92 views
2

我想了解同步對象的概念。使用Java Cert Book中的這個示例,您是否可以幫助我理解以下兩段代碼之間的行爲差​​異(其中一個是我們在要保護的方法/操作與競爭條件同步的對象與另一個我們使用的對象之間進行同步輔助對象作爲鎖來實現相同的目標):瞭解Java中的同步塊

1.

class Client { 
    BankAccount account; 

    public void updateTransaction() { 
    synchronized (account) {  
     account.update();   // update is safe because of lock on account obj 
    } 
    } 

    public double withdrawFunds() { 
    double amt; 
    synchronized (account) { 
     account.calculateInterest(); 
     amt= account.withdraw(); 
    } 
    return amt; 
    } 
} 

2.

class Client { 
    BankAccount account; 
    Object lock = new Object(); 

    public void updateTransaction() { 
    synchronized (lock) {  
     account.update();   // update is safe because of a lock   
    } 
    } 

    public double withdrawFunds() { 
    double amt; 
    synchronized (lock) { 
     account.calculateInterest(); 
     amt= account.withdraw(); 
    } 
    return amt; 
    } 
} 

回答

1

區別在於其他線程在系統中執行的操作。在第一種情況下,如果有任何理由說明爲什麼某些其他邏輯(在其他代碼中定義)不應該與updateTransaction方法並行執行,那麼該邏輯也可以在帳戶對象上同步。相反,如果某些不相關的代碼在與updateTransaction無關時也將帳戶用作鎖,則可能會發生虛假同步。

在第二種情況下,鎖對象只對Client類可見,所以您可以保證唯一進行的同步是您在此類中指定的內容。

我同意Peter Lawrey的看法,最好的方法是將同步邏輯封裝在一個有意義的地方,並使用私有/受保護的可見性鎖定對象。

1

在這兩種情況下,沒有什麼區別,只是風格上的差異。

如果可以更改帳戶,則存在潛在的問題,可能會在錯誤的對象上同步。讓這個屬性成爲最終的,你很好去。

3

這兩個都會拋出NullPointerExceptions,但只能在不同的地方。

您應該始終在永遠不會爲空(最終)的不可變引用上進行同步。

我想你的問題的答案是,該帳戶可能會改變一個給定的客戶端(假設有一個setter),但永遠不應該鎖定。同樣,保證這一點的唯一方法就是將其標記爲最終。

2

更好的方法是避免在封裝時暴露鎖定。

class Client { 
    final BankAccount account; 

    public void updateTransaction() { 
     account.update();   // update is synchonized. 
    } 

    public double withdrawFunds() { 
    return account.calculateInterestAndWithdraw(); 
    } 
} 
+0

問題的目的是瞭解鎖定/同步如何工作。 – JavaUser201

+1

希望你也能更好地理解最佳實踐。 ;) –

0

我會使用選項2,只是使鎖定對象最終。賬戶對象可能可以改變,特別是如果客戶可以有多個賬戶。如果您使用最終鎖定對象,則即使帳戶對象更改爲其他實例,也會確保對該帳戶的任何更改都進行了同步。

1

區別在於誰持有鎖。

第一種情況是比較好的,因爲在其他線程中也可以共享帳戶的相同參考,例如在類Manager中,並且如果此經理需要訪問該帳戶,應該嘗試自己鎖住該鎖在任何情況下,Client線程都會嘗試同時訪問該帳戶。

在第二個代碼中,Manager需要鎖定lock對象,以防止損壞數據,所以它需要獲取帳戶和鎖。

最好的方法是封鎖帳戶裏面的鎖。