W przypadku współbieżności zawsze trudno jest podać dobre odpowiedzi. To bardzo zależy od tego, co naprawdę robisz i co naprawdę ma znaczenie.
Z mojego zrozumienia, ruch gracz obejmować:
1 Updading pozycję gracza.
2 Usuwanie odtwarzacza z poprzedniego pola.
3 Dodawanie gracza do nowego pola.
Wyobraź użyć kilka zamków w tym samym czasie, ale nabyć tylko jedną na raz: - kolejny gracz może doskonale wyglądać w nieodpowiednim momencie, w zasadzie między 1 & 2 lub 2 & 3. Niektóre gracz może pojawić się disapeared z planszy na przykład.
Wyobraź sobie DO imbricked blokowania tak:
synchronized(player) {
synchronized(previousField) {
synchronized(nextField) {
...
}
}
}
Problemem jest ... To nie działa, zobacz ten kolejność wykonywania przez 2 wątków:
Thread1 :
Lock player1
Lock previousField
Thread2 :
Lock nextField and see that player1 is not in nextField.
Try to lock previousField and so way for Thread1 to release it.
Thread1 :
Lock nextField
Remove player1 from previous field and add it to next field.
Release all locks
Thread 2 :
Aquire Lock on previous field and read it :
wątku 2 myślę, że gracz 1 został usunięty z całej planszy. Jeśli jest to problem związany z aplikacją, nie można użyć tego rozwiązania.
Dodatkowy problem z zablokowaniem blokującym: wątki mogą zostać zablokowane. Wyobraź 2 graczy: wymieniają swoją pozycję dokładnie w tym samym czasie:
player1 aquire it's own position at the same time
player2 aquire it's own position at the same time
player1 try to acquire player2 position : wait for lock on player2 position.
player2 try to acquire player1 position : wait for lock on player1 position.
=> Obaj gracze są zablokowane.
Najlepszym rozwiązaniem moim zdaniem jest użycie tylko jednego zamka, na cały stan gry.
Gdy gracz chce odczytać stan, blokuje cały stan gry (płyta &) i tworzy kopię dla własnego użytku. Może następnie przetwarzać bez blokady.
Gdy gracz chce zapisać stan, blokuje cały stan gry, zapisuje nowy stan, a następnie zwalnia blokadę.
=> Blokada jest ograniczona do operacji odczytu/zapisu stanu gry. Gracz może wykonać "długie" badanie stanu deski na swojej własnej kopii.
Zapobiega to jakiemukolwiek nieodpornemu stanowi, takiemu jak gracz na kilku polach lub nie ma go wcale, ale nie przeszkadza graczowi w używaniu "starego" stanu.
Może wydawać się dziwne, ale jest to typowy przypadek gry w szachy. Kiedy czekasz, aż inny gracz się ruszy, zobaczysz planszę jak przed ruchem. Nie wiesz, jaki ruch wykona drugi gracz i dopóki on się nie poruszy, będziesz pracował nad "starym" stanem.
Ponieważ operacje są bardzo krótkotrwałe, może się okazać, że użycie tylko jednego globalnego zamka działa na tyle dobrze, że nie można stwierdzić różnicy. Korzystanie z jednego zamka może ograniczać się do 200 000 ruchów na sekundę (czy to wystarczy?), Ale może uprościć kod i nie dostaniesz zakleszczenia. –