2010-07-30 24 views
40

我知道同步方法和同步塊之間的區別,但我不確定關於同步塊部分。lockObject上的synchronized和使用此鎖作爲鎖之間有什麼區別?

假設我有這樣的代碼

class Test { 
    private int x=0; 
    private Object lockObject = new Object(); 

    public void incBlock() { 
    synchronized(lockObject) { 
     x++; 
    } 
    System.out.println("x="+x); 
    } 

    public void incThis() { // same as synchronized method 
    synchronized(this) { 
     x++; 
    } 
    System.out.println("x="+x); 
    } 
} 

在這種情況下就是使用lockObject和使用爲鎖定的區別?它似乎對我來說是一樣的。

當你決定使用同步塊時,你如何決定哪個對象是鎖?

+5

我找到了答案,我的問題在 http://stackoverflow.com/questions/3047564/java-synchronized-method-lock-on-object-or-method 如果你看一下答案,這是非常清楚,如果有2個線程(t1和t2),其中t1調用x.addA(),t2調用x.addB()。如果addA和addB都將此作爲鎖,則x.addA()和x.addB()不能同時運行。 而如果如果ADDA和ADDB使用不同對象的鎖,這兩個方法可以同時運行 – GantengX 2010-07-30 07:11:40

+2

只是爲了檢查的內容:在上面的例子中,當您使用lockObject有效防範訪問x是不是有一種情況,另一個線程可能在同步塊之後但在println之前進入並再次增加x?即你真的需要在同步塊內的println嗎? – 2010-07-30 08:40:42

+1

啊,我應該把它放在同步塊中,但我已經回答了我自己的問題:D – GantengX 2010-08-04 11:34:37

回答

54

就我個人而言,我幾乎從不鎖定「這個」。我通常鎖定一個私人蔘考,我知道沒有其他代碼會鎖定。如果你鎖定「this」,那麼任何知道你的對象的其他代碼可能會選擇鎖定它。儘管不太可能發生,但它肯定會發生 - 並且可能導致死鎖,或者只是過度鎖定。

你鎖定的東西沒有什麼特別的神奇 - 你可以有效地將它看作一個令牌。任何使用相同標記鎖定的人都將嘗試獲取相同的鎖定。除非你想想要其他代碼能夠獲得相同的鎖定,請使用私有變量。我會鼓勵你使變量final - 我不記得我已經有史以來想要改變對象的生命週期鎖定變量的情況。

+0

可以詳細說明嗎? 說類'A'具有類'B'的實例。現在'B'有一些成員變量。當'A'調用'B'的任何方法時,它會鎖定這個/實例成員......對吧?手段鎖定'B'本身或其成員的實例......你能解釋一下這個區別嗎? – Parth 2010-07-30 07:08:58

+1

@Paarth:你的評論不清楚 - 你的意思是*應該*'B'鎖定每個方法的私人鎖?這取決於班級本身的目的。說實話,大多數類不需要嘗試線程安全。 – 2010-07-30 07:24:04

+0

嗯,所以我需要做同步方法,它會使用私有成員對象而不是'this'...對嗎?好的... – Parth 2010-08-04 05:13:37

0

在這種情況下,您選擇鎖定哪個對象並不重要。但是您必須始終使用相同的對象進行鎖定以實現正確的同步。上面的代碼不能確保正確的同步,因爲您曾經使用'this'對象作爲鎖,接下來使用'lockObject'作爲鎖。

+0

我理解,因爲它使用了不同的方法,不同的鎖,這不是一個正確的同步,我只是想了解使用「這個」和「lockObject」的鎖 – GantengX 2010-07-30 07:06:49

+0

哦..對不起,誤解你的問題之間的區別。因此,答案與Jon Skeet所回答的相同。 – Gopi 2010-07-30 07:09:30

4

Effective Java Second Edition的項目67是避免過度同步,因此我會同步私人鎖定對象。

+0

它不回答這個問題(使用'synchronized'或'Locks'),沒有真正的解釋,斷開的鏈接([archived version](http://web.archive.org/web/20090904194857/http://java。 sun.com/docs/books/effective/index.html))。 Downvoted。 – 2017-08-12 06:24:44

1

Java中的每個對象都可以充當監視器。選擇一個取決於你想要的粒度。選擇'this'具有其他類也可以在同一監視器上同步的優點和缺點。我的建議是儘量避免直接使用synchronize關鍵字,而是使用java.util.concurrency庫中更高級別且具有良好定義的語義的結構。這本書具有非常顯着的專家很多在這偉大的意見:

Java併發實踐 http://amzn.com/0321349601

9

我有,當我在閱讀Java併發在實踐中,同樣的問題,我想我要補充對Jon Skeet和spullara提供的答案有一些補充。

下面是一些示例代碼,在執行doStuff(ValueHolder)方法時,即使是「快速」setValue(int)/getValue()方法也會阻止該方法。

public class ValueHolder { 
    private int value = 0; 

    public synchronized void setValue(int v) { 
     // Or could use a sychronized(this) block... 
     this.value = 0; 
    } 

    public synchronized int getValue() { 
     return this.value; 
    } 
} 

public class MaliciousClass { 

    public void doStuff(ValueHolder holder) { 
     synchronized(holder) { 
      // Do something "expensive" so setter/getter calls are blocked 
     } 
    } 
} 

使用this用於同步的缺點是其它類可以(不是通過this,當然)到您的類的引用同步。惡意或無意使用​​關鍵字,而在你的對象引用鎖定可能會導致你的類不良行爲併發使用下,作爲外部類可以有效地阻止你this -synchronized方法並沒有什麼可以做,(在你的類)在運行時禁止此操作。爲了避免這種潛在的隱患,您可以在private final Object上同步或使用java.util.concurrent.locks中的Lock接口。

對於這個簡單的例子,你可以交替使用AtomicInteger,而不是同步的setter /吸氣。

相關問題