2016-07-30 39 views
4

這是從Joshua Bloch編寫的一本書中摘取的。如果線程試圖獲取它已經擁有的鎖,會發生什麼情況?

我不是英語母語的人,因此有理由要求澄清疑問。

由於內在鎖是可重入的,如果一個線程試圖 收購它已經持有鎖,請求 成功。重入意味着每個線程在 而非**每個調用的基礎上獲取鎖。

通過每個調用的基礎,他意味着每個方法調用? 考慮片段:

class Factoriser{ 

     public synchronized void doSomething(){ 
      // code goes here 
     } 
} 

假設有一個線程A,並且能夠在具有實例方法doSomething的對象獲取鎖()。由於某種原因,相同的線程線程A再次獲得對同一個對象實例方法doSomething()的鎖(想象前一個鎖還沒有被釋放)。

如果我正確理解了Joshua的說法,那麼即使有2個方法調用/調用,也只會有一個鎖。我的理解是否100%正確。請舉例說明。我很困惑,因爲提交人在下面的段落中澄清了這一點,這使我更加困惑。

重入是通過將每個鎖與一個採集計數和一個擁有線程相關聯來實現的。當計數爲零時,該鎖被認爲是不受支持的。當線程獲取先前未釋放的鎖定時,JVM將記錄所有者 並將採集計數設置爲1。如果同一個線程 再次獲取鎖定,則計數遞增,並且當擁有線程退出同步塊時,計數遞減 。當計數達到零時,鎖定被釋放。

如果重入/鎖獲取不是基於每個調用的基礎,那麼爲什麼JVM將對上述場景設置爲2來完成計數?

+2

這是一個** ** ** ** ** **。事實上,**有如此多的大膽**,它變得毫無意義**和**分心**。 – Andreas

+0

每個對象只有一個鎖。任何數量的調用只需要相同的鎖(成功)。當最後一個鎖被釋放時,該對象不再被鎖定。爲什麼這很難? – markspace

+0

@Andreas:謝謝。刪除。 –

回答

2

該計數器用於匹配鎖定獲取和排泄。該鎖可以被釋放,只有當計數器爲0標記的方法foo()作爲​​並調用它的對象上obj等同於以下塊:

// calling obj.foo() 
synchronized(obj) { 
    // Do the foo-work 
} 

假設我們有兩個同步方法:foo()bar()和後者被稱爲前者。調用將具有以下結構:

final FooBar obj = new FooBar(); 

// calling obj.foo() 
synchronized(obj) { // 1. here the lock is acquired, the counter is set to 1 

    // do some foo-work 

    // calling obj.bar() 
    synchronized(obj) { // 2. the same lock object, the counter is set to 2 
     // do the bar-work 
    } // 3. the counter is set to 1, the lock is still not released 

    // continue doing the foo-work 
} // 4. the counter is 0, the lock is released 

在不施加反,在步驟3中,我們將釋放,因爲我們仍然在外部同步塊這將是錯誤的鎖定。所以,櫃檯需要正確實施再入口。

+0

整個對象是否被鎖定?或者只有那些標記爲該對象同步的方法。 –

+0

我不確定我完全理解你的問題。所有同步方法都使用相同的鎖對象 - 調用這些方法的對象(靜態同步方法使用'Class'對象)。所以,你可以說整個對象都被鎖定了。但是,不標記爲已同步的方法仍然可以被調用,而不管活動鎖定。只要將每個同步方法想象爲一個非同步方法,但如同我在答案中所示,將其置於一個與此方法被調用的對象同步的塊上,並且許多事情將更容易理解。 –

+0

重要的是方法本身不會被鎖定。它們只能被一個特定的對象(或者一個類,如果它們是靜態的)在已經在某個線程中調用並且仍然有效的情況下「鎖定」。同時,另一個線程可以在另一個對象上調用相同的方法,並且不會被阻塞,因爲它將使用另一個對象進行鎖定。所以,它是鎖定的對象,而不是方法。但是這些鎖僅影響使用同一對象的同步方法和同步塊。 –

相關問題