2014-12-02 167 views
0

我有一個A類型的對象的數組。每個對象都有一個值和對數組中下一個對象的引用。它還有一個方法process,它控制對象的值和下一個(下一個)對象的值。同步鄰居

public class A{ 
    private int value; 
    private A next; 

    public void process(){ 
     //manipulates the value of this and of next 
    } 
} 

在我的主要方法我已經創建B類型的多個線程,其中要求在陣列中的某些對象的process -method。

因此,我想創建一個圍繞該值的鎖。不應允許多個線程同時操縱某個對象的值。但問題是,如果我聲明process-方法​​,那麼仍然線程處理array[0]和處理array[1]能夠操縱array[1]的值。撥打array[1].process(),應等待,直至完成所有array[0].process()array[1].process()

如何創建每個鄰居對的鎖?

回答

1

已有process獲取兩個鎖:一個用於此對象,另一個用於下一個鎖。類似這樣的:

public void process() { 
    synchronized (this) { 
     synchronized (next) { 
      // manipulate the value of this and of next 
     } 
    } 
} 

這個答案應該會在你的腦海裏產生一個巨大的紅旗。 任何當你獲得多個鎖,你必須說服自己,他們不會死鎖!

只有兩個線程試圖以不同的順序獲取鎖時,纔會發生死鎖(即一個鎖A然後B鎖,另一個鎖鎖B然後鎖A)。在這種情況下,不可能發生 - 先前的對象始終在其下一個對象之前被鎖定。

因此,當調用array[0].process()時,它鎖定array[0]array[1]。當調用array[1].process()時,它將嘗試鎖定array[1],這將會阻止,直到array[0].process()完成。發生這種情況時,它將獲得array[1]上的鎖定,然後嘗試獲取array[2]上的鎖定。

雖然這仍然有可能導致死鎖。如果process中的代碼激活一個新線程,然後嘗試在前一個對象上調用process,然後嘗試加入該線程,則該線程會死鎖。例如,如果array[1].process()這樣做,那麼該線程將嘗試獲取array[0]array[1]的鎖。直到array[1].process()完成,它將無法執行此操作,直到線程返回並因此死鎖纔會發生。

出於這個原因,你應該非常小心讓process是「可插拔」(如,有人通過在接口或延伸的方法來確定操作是如何實現的。一般情況下,執行任何類型的「外部代碼」以這種方式在鎖中完成時是危險的。

但是,如果process完全在您的控制之下,並且不旋轉任何線程,那麼您應該沒問題,因爲其中的鎖被收購。

在這樣的地方有一個有點微妙的舞蹈的情況下,它的情況並不少見無法獲取上this的鎖,只是應景的自定義對象上:

public class A { 
    private final Object lock = new Object(); 
    private int value; 
    private A next; 

    public void process() { 
     synchronized (lock) { 
      synchronized (next.lock) { 
       // etc 
      } 
     } 
    } 
} 

這可以保護你從別人進入並同步你的一個物體,並擾亂那個微妙的舞蹈。它還可以提供給任何正在閱讀代碼的人的視覺提醒,即有關同步的一些有趣的事情。