2009-08-30 42 views
1

對以下內容有何理解?
我已經通過this後在SO,但仍然在虧損組裝它。使用線程中的同步

代碼1:

synchronized(this){ 
// some code 
} 

碼2:

Object lock = new Object(); 

synchronized(lock){ 
// some code 
} 

任何教程,或者某些環節來解釋同步像他們解釋給孩子?

回答

3

在已經給出的其他優秀答案中沒有提到的一件事是Code1和Code2之間的區別。在code1中,同步位於找到代碼的對象的實例上,而在code2中,它位於對象內的特定鎖對象上。

如果只有在外部類的兩個同步塊,還有的兩者之間沒有功能差異,但考慮到這一點:

 
class CodeOneClass { 
    ... 
    synchronized(this) { // or merely "synchronized" - it defaults to this 
     first protected code block 
    } 
    ... 
    synchronized(this) { 
     second protected code block 
    } 
... 
} 

class CodeTwoClass { 
    ... 
    Object lock1 = new Object(); 
    synchronized(lock1) { 
     first protected code block 
    } 
    ... 
    Object lock2 = new Object(); 
    synchronized(lock2) { 
     second protected code block 
    } 
... 
} 

如果兩個線程試圖使用CodeOneClass的同一個實例,其中只有一個可以同時在兩個受保護的代碼塊中的任一個中。

但是有了第二個習慣用法,您可以靈活地說,一個線程處於第一個保護區,另一個處於另一個線程中是安全的。請注意,如果鎖相同(在同一個鎖對象上同步),則行爲將作爲第一個鎖。

還有其他的區別。一些作家開始用同步(這)指出的問題 - 我想指出你另一篇文章在這裏SO: Avoid synchronized(this) in Java?

我強烈建議你閱讀它,和三個職位它鏈接到。

+0

其他答案也很好?希望我可以選擇更多正確/有用的答案? – 2009-09-03 13:17:38

6

基本上,Java中的每個對象都有一個「鎖」。

當一個線程到達一個調用synchronized(something)的地方時,它必須在繼續之前獲取某個東西的鎖。如果你想一次只允許一個線程修改對象的狀態,最明顯的是同步該對象的鎖定。如果允許不同的方法被並行調用,那麼你需要不同的鎖。

如果你寫同步(this),或者只是同步,線程必須獲取與當前對象(調用哪個方法)相關的鎖。

請注意,自Java 5.0以來,併發包提供了可用於代替同步的正確locks

+0

您能否提供一些示例或鏈接以進一步理解該主題,謝謝! – 2009-08-30 15:25:56

+1

你讀過這個嗎? http://java.sun.com/docs/books/tutorial/essential/concurrency – Zed 2009-08-30 15:28:42

+0

我會,現在!謝謝! – 2009-08-30 15:31:48

3

將代碼放在​​塊中本質上意味着「一旦此代碼開始運行,其他需要使用此對象的代碼不能同時運行。」

所以,如果線程#2是你的code2塊執行的代碼,當涉及到synchronized(lock)代碼它有效地環顧四周,在所有其他線程,以確保沒有其他正在運行「同步」的代碼與lock目前的對象。線程#1肯定同時運行一些的代碼,但它可能是完全無關的代碼。如果是這樣,第二線程開始運行你的「some code」是安全的。同時,如果線程#1到達synchronized(this)塊,它也必須暫停並查看是否有任何其他線程正在使用this。如果thislock是同一個對象,則說明存在問題。我們被告知只有一個線程可能同時使用該對象(在同步塊中)。然而,線程#2已經在使用它。線程#1將不得不等待......並等待......並等待......直到最終線程#2完成。然後我們可以繼續。

最終的結果是,一次只能運行一個​​塊(當然有特定的對象)。

+0

很好解釋! – 2009-08-30 15:39:06

2

假設你有一個Account對象,它有一個方法:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException 
{ 
    if (accountBalance >= debitAmount) { 
     accountBalance -= debitAmount; 
     beneficiary.credit(debitAmount); 
    } 
    else { 
     throw new InsufficientFundsException(); 
    } 
} 

現在,假設你有100歐元的餘額帳戶,你會得到兩次嘗試了70歐元借記它。如果兩個借方發生在同一時間,你可以得到一個競爭條件這樣的:

  • 首先借記支票賬戶餘額:100> = 70,所以成功
  • 二借記支票賬戶餘額:100 > = 70,所以成功
  • 第一次借記執行;賬戶餘額變爲30
  • 第二次借記執行;賬戶餘額變爲-40。 不應該被允許

我們可以通過對Account對象的鎖同步預防事務的這種可怕的狀態:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException 
{ 
    synchronized (this) { 
     if (accountBalance >= debitAmount) { 
     accountBalance -= debitAmount; 
     beneficiary.credit(debitAmount); 
     } 
     else { 
     throw new InsufficientFundsException(); 
     } 
    } 
} 

這可以確保在賬戶餘額的測試和借記能不會因帳戶餘額的另一項測試而中斷。

Sun Java tutorial是開始獲取併發和鎖定信息的好地方。