2009-12-27 51 views
2

我有這些類,我用它來創建,我想在運行時併發複方編輯

Class Person 
    String name 
    Pet[] pets 

Class Pet 
    String name 
    Person[] owners 
    boolean neutered 

存儲起初,我用這些包含HashMap將它們存儲

HashMap people 
HashMap pets 

對象,但我想要的使實現併發所以我改變這些地圖像這樣

ConcurrentHashMap people 
ConcurrentHashMap pets 

我用"compareAndSet in a while loop" pattern進行原子更新。

但我仍然有一個問題,因爲我的People地圖中的每個人都有Pets地圖中的相關寵物。爲了保持更新原子我加ReentrantReadWriteLocks,這樣我可以同時更新與相關Pet對象People對象。

ConcurrentHashMap people 
ConcurrentHashMap peopleLocks 
ConcurrentHashMap pets 
ConcurrentHashMap petLocks 

現在,當我在多個記錄進行編輯,我首先抓住所有的寫鎖,然後我讓我的編輯,最後釋放寫入鎖。這可確保在進行更新時不會讀取數據。

changePetNames(Person person, Pets[] pets, String[] names) { 
    // get Person lock 
    // get Pet locks 
    // make updates 
    // release locks 
} 

neuter(Pets[] pets) { 
    // get Pet locks 
    // make updates 
    // release locks 

然後我有我所有的編輯方法實現同步一個物體上,使競爭的修改將不會死鎖

private final Object leash = new Object(); 
changePetNames(Person person, Pets[] pets, String[] names) { 
    synchronized(leash) { 
     // get Person lock 
     // get Pet locks 
     // make updates 
     // release locks 
    } 
} 

neuter(Pets[] pets) { 
    synchronized(leash) { 
     // get Pet locks 
     // make updates 
     // release locks 
    } 
} 

所以現在我有運行的存儲,允許併發讀取和寫入同步。我的問題是,是否有辦法使寫入同時進行,同時保護人與寵物之間的關係。

+0

謝謝,meriton。我重新陷入僵局。 – Rapier 2009-12-27 18:53:02

回答

2

代替皮帶對象上同步的,你可以在People人對象上同步。這可以同時改變不同的人和他們的寵物,同時阻止一個人和她的寵物的同時變化。

PS,從外觀上來看你的鎖定系統似乎有點過於複雜。在假設的人 - 寵物是1對多的關係,一個人可以有很多寵物,但任何寵物只有一個所有者,只有synchonizing人物對象上可能是你需要的一切。

PS2,命名是很重要的,你的類名是多元的,我想用PersonPet代替PeoplePets會更好地描述使你的代碼更容易理解的概念。

編輯 方法,如neuter,僅拍攝寵物,而無需更改數據的所有者會,讓他們併發,對寵物的同步,但是這意味着:

  • 當您編輯一個人和她的寵物,你需要兩個人與寵物同步謹防寵物只改變
  • 有時寵物可以被鎖定,同時與寵物的人也需要鎖定

當一個線程有一個寵物鎖並嘗試獲得一個人鎖而另一個線程擁有該人鎖並嘗試獲取寵物鎖時,上述情況可能會導致死鎖情況。我的解決辦法是對業主進行同步,即使只寵物需要改變,這意味着changePetNames和中性會是什麼樣子:

changePetNames(Person person, Pets[] pets, String[] names) { 
    synchronized(person) { 
     // make updates 
    } 
} 

neuter(Pets[] pets) { 
    for (Pets pet: pets) { 
     // make sure pets owner exists 
     synchronized(pet.getOwner()) { 
      // make updates 
     } 
    } 
} 

這樣沒有死鎖可能會發生,如果你從來沒有嵌套同步動作不同的人。

EDIT2 當業主的寵物是一個多對多的關係,你需要對人員和寵物的獨特組合,這將重現您AQUIRE更新已經寫鎖的represenatation同步。我的結論是,如果可以確保不發生死鎖,那麼不需要額外的同步租約。

如果兩個線程想要獲得另一個之前已獲得的鎖,就會發生死鎖,因此如果可以確保鎖總是以相同的順序獲得,則此問題不會發生。

如果你想補充一個唯一的ID創作既人與寵物和每次更新中始終遞增的順序設置AQUIRE鎖,不能發生死鎖的情況:

changePetNames(Person person, Pets[] pets, String[] names) { 
    // sort Person ID's 
    // get Person lock in ID sequence 
    // sort Pet ID's 
    // get Pet locks in ID sequence 
    // make updates 
    // release locks 
} 

應該做的伎倆。

+0

我修改了問題以顯示事件,儘管人與寵物之間存在某種關係,但某些修改與人員無關。在這種情況下,人們的同步將對只需要訪問寵物的修改徵求額外的要求。 – Rapier 2009-12-27 17:37:20

+0

您的評論讓我意識到我需要人與寵物之間的多對多關係,所以我修改了這個問題。 – Rapier 2009-12-27 18:26:53

1

然後我有我所有的編輯方法之一對象 同步,使 競爭的修改將不會鎖定每個 等了。

現在所有的編輯「互相鎖定」。這是一種改進?

我不明白你爲什麼不能簡單地忽略那個同步。在Person上獲取ReadWrite鎖已經可以防止衝突的併發更新(除非寵物更改了所有者,這可以通過對原始所有者進行額外的同步來處理)。

編輯:啊,「對方鎖定」是指「僵局」 ......

Wikipedia's article on the Dining Philosophers problem討論了避免死鎖的幾種典型技術。您的案例中最簡單的解決方案可能是「資源層次結構解決方案」,其中的對象的總排序要同步到。例如,如果按升序(唯一)ID的順序鎖定對象,然後執行該操作,然後釋放所有鎖定,則不會發生死鎖。 (因爲持有「最高」鎖的線程不會受到任何其他線程的阻礙。)

+0

我的編輯例程可以同時抓取多個寵物,有時還會抓取多個人。因此,如果兩個編輯線程競爭對象A和B,則有可能一個線程獲取A而另一個線程獲取B,從而導致它們最終陷入僵局。圍繞皮帶的同步修復了這一點。 – Rapier 2009-12-27 17:09:38

+0

啊,現在我明白你的意思是「互相鎖定」。我編輯了我的答案,以包含更好的併發性的死鎖保護方案。 – meriton 2009-12-27 17:40:23

+0

我修改了問題以顯示事件,儘管人與寵物之間存在某種關係,但某些修改與人員無關。因此,雖然資源層次結構對changePetNames()起作用,但對於neuter()而言,這成爲一個問題。 – Rapier 2009-12-27 17:51:26