2017-10-08 20 views
2

從多重編程通過赫利希藝術:爲什麼一個線程在拿到鎖的同時測試一個條件/屬性,而不是在獲取鎖之前?

假設一個線程 要等到一定的屬性保存。 線程測試屬性,而 持有鎖。如果該屬性不成立,則線程調用await()至 釋放該鎖並休眠,直到被另一個線程喚醒。

1 Condition condition = mutex.newCondition(); 
2 ... 
3 mutex.lock() 
4 try { 
5  while (!property) { // not happy 
6   condition.await(); // wait for property 
7  } catch (InterruptedException e) { 
8   ... // application-dependent response 
9  } 
10 ... // happy: property must hold 
11 } 

圖8.2如何使用Condition對象。

爲什麼線程調用mutex.lock()它測試的屬性(如果該屬性不成立,線程調用await()),而不是前後?

謝謝。

+2

因爲屬性可以在檢查和鎖定之間改變。 – shmosel

回答

2

如果你把它改爲:

while (!property) { 
    mutex.lock(); 
    condition.await(); 
    mutex.unlock(); 

最大的問題是,如果財產價值線

while (!property) { 

與線之間變化

mutex.lock(); 

然後你當它已經處於合格狀態時,會等待房產改變。

如果假設在佔用鎖互斥然後在你的問題的例子,你只能改變屬性,你不能叫

condition.await(); 

而財產處於開通狀態。

爲了詳細說明這個假設,來自問題的示例代碼通常會以某種方式來設置屬性的值。這可能是沿着

void setProperty(boolean newproperty) { 
    mutex.lock(); 
    property = newproperty; 
    condition.signalAll(); 
    mutex.unlock(); 
} 

行沒有這個第二部分,你可以永遠機制保障,你只叫

condition.await(); 

而屬性爲false。

+0

謝謝。爲什麼「你認爲你只能在鎖住互斥鎖的情況下改變屬性,然後在你的問題中的例子」? – Ben

+0

因爲如果您可以在不鎖定互斥鎖的情況下更改屬性,那麼您無法保證在檢查它和調用await之間不會在另一個線程上更改它。 –

1

獲取鎖的一件事就是創建一個內存屏障,以便不使用可能已陳舊的緩存值檢查該條件。

同時獲取鎖定可確保檢查的值不會被其他線程同時更改。否則,線程可以測試條件並繼續獲取鎖,然後查找在獲取鎖的時候更改的條件。無論如何,線程最終需要檢查鎖定。

線程想要確定鎖定對象的狀態,然後修改該狀態,同時保證該狀態不會由於其他線程的干擾而從它下面更改。這意味着它必須鎖定檢查和行動。線程在不成功的檢查後等待(釋放鎖直到發出信號),然後在下一次檢查之前獲取鎖。一旦檢查成功,它將持有該鎖,直到它可以完成對鎖定對象的操作。

只有當檢查成功時(例如添加到有界緩衝區),對鎖定對象執行的操作纔有意義。或者該操作可能涉及多個更改,其中所有更改需要一起應用(如果鎖定的對象具有不是爲併發訪問而設計的數據結構,如ArrayList,數據結構需要多個步驟才能添加元素,並且干擾可以破壞數據結構)。

相關問題