2010-07-29 118 views
0

我在理解私人鎖的概念一點困難:線程和同步

public class MyObject { 
    private final Object lock = new Object(); // private final lock object 

    public void mymethod() { 
    synchronized (lock) { // Locks on the private Object 
     // ... 
    } 
    } 
} 

在上面的代碼中,鎖被獲取的不同的對象上,但在當前的對象的代碼是由同步塊把守。現在,除了上面代碼中的鎖對象之外,它也可以是任何其他對象。我發現很難理解另一個對象上的鎖是如何與當前對象中的synchronized關鍵字相關的。國際海事組織,它可能會導致一些惡意代碼鎖定任何對象。允許鎖定其他對象的基礎是什麼?

回答

0

鎖總是在對象上。

syncronized block的用途是用鎖來防護對象(一個與block關聯),所以這意味着只有鎖定了對象的線程才能進入這個block。

它沒有什麼問題,在代碼中可能會出現這種情況,您不需要同步完整的方法,只需要幾行代碼即可。

同步塊的一種用法是在多線程env中需要改變對象狀態(和其他與之相關的對象)的情況,但是這個對象的類沒有同步方法來改變對象的狀態。 在這種情況下,使用這種塊來實現同步。

1

那麼你可以,例如,有一個對象,管理兩個列表。

如果在線程B更改列表2時線程A可能更改列表1,那麼您將使用不同的鎖定,而不是在擁有的對象上同步。

基本上顯式的鎖允許更精細的行爲控制。

+0

在這種情況下,我可以在這個類中創建一個或多個內部類並獲取一個鎖。 – Nirmalya 2010-07-29 17:13:11

0

你是對的,你提供的代碼可以鎖定任何對象。但是,它沒有。它鎖定在一個私人實例字段上 - 一個只有該實例可以訪問的字段。這意味着沒有其他代碼可能會鎖定該對象。在這種情況下,你並沒有鎖定其他對象,因爲如果其他代碼被鎖定,那麼你必須等待它(並且它可能永遠不會被釋放)。

「惡意」代碼可能會鎖定任何對象,但只會在其他代碼試圖鎖定同一對象時傷害其他代碼。我創建自己的私人對象進行鎖定,可以保護自己免受其他代碼的鎖定。

+0

現在仍然存在的問題是我可以鎖定任何對象。我可以鎖定某些實用程序應用程序類並在synchronized塊下執行非常昂貴的操作。現在,如果域類具有任何同步方法,那麼對該方法的訪問將一直等到鎖被釋放。相反,我可以創建一個內部類並鎖定它。 – Nirmalya 2010-07-29 17:11:27

+0

具有一些同步方法的域類會自己鎖定_never_(無論是「Clazz.class」還是「this」)。它只會鎖定一些私有的對象(如私有實例字段)。 被鎖定的對象更像是一個令牌,一個說話棒,只是說些什麼,「而我堅持這一點,只有我可以採取行動」。這不關乎整個班級阻止任何事情。 所以當鎖定一個類時,比如'String.class',你實際上並不會阻塞String類中的任何東西。 – EliThompson 2010-07-29 17:20:23

+0

也許我無法正確表達我的關注。換句話說,我有一個有另一個類B的類A,現在說A類是否鎖定了類B的一個對象,並在Synchronized塊下面執行了一長串代碼。現在,當類A中的同步方法保護的代碼正在運行時,如果另一個線程想要訪問任何類B的方法,那麼如果類B的方法是同步的,那麼可能會產生什麼效果。 – Nirmalya 2010-07-29 18:22:55

0

​​實際上對多線程環境有效。這種方法是爲了允許系統中的併發。

當一個對象被同步時,第一個「接觸」該對象的線程會在該對象上放置一個,直到該對象使用該對象完成並釋放它爲止。它可以防止許多線程同時更改同一個對象。

1

IMO,它可能導致一些惡意代碼鎖定任何對象。

這實際上是問題的癥結所在。

使用如圖所示的單獨鎖定對象(關鍵是,使用private),那麼只有MyObject類中的代碼才能夠在該監視器上獲取鎖定 - 因此您可以看到所有可能參與鎖定的代碼涉及這個類的情況。

走向了另一個極端,如果您獲得了上例如鎖一個常量字符串,然後任何代碼,在同一個JVM中鎖定在同一個字符串中的任何地方都會與你的類競爭 - 這幾乎肯定不是目的,並且很難追蹤。

基本上 - 如果你鎖定一個非私有對象上,那便成爲你的公共接口的一部分,有效。有時候這是有意的(例如,對於Collections.synchronizedFoo對象,他們聲明可以在對象本身上進行同步以粗化鎖定)。通常不是,只是一個疏忽。

你應該讓你的鎖監視器私人的,出於同樣的原因,你保持私有成員變量私人 - 防止其他代碼的事情搞亂,他們不應該。而this基本上從不私人。

0

鎖應該是私有的當且僅當不會有任何理由與您的類中的任何鎖,而沒有線程實際上是在你的類(或代碼在你的類從代碼中調用)運行的代碼舉行。如果您需要例如允許某人在操作之間保持對對象的獨佔控制,則必須公開一個鎖。這帶來了很多潛在的問題,包括死鎖,所以通常最好的做法是設計你的接口和契約,以便不需要這種擴展鎖定。

順便說一句,注意,執行回調,而持有鎖略大於曝光鎖不那麼危險,但幅度不大。您可以消除主叫方可能獲得鎖的危險,並簡單地將其忘掉,但死鎖的危險依然存在。